Compare commits

...

143 Commits
v1.2.1 ... JTA

Author SHA1 Message Date
Jason T Alborough
5a2b1f431f Changes to essentials framework 2019-03-07 12:09:03 -05:00
Jason T Alborough
6253d4becf Generic LightingBRidge. Adds a check for 0 values. Now recalls Analog scene value - 1 2019-03-06 15:49:20 -05:00
Jason T Alborough
1bb9bfab70 Adds QscDsp Eiscbridge 2019-03-06 15:28:35 -05:00
Jason T Alborough
6aae1c6613 Adds TvOne Eisc Bridge.
Fixes line endings on the DmChassisControllerBridge (per prompt)
2019-03-06 13:01:35 -05:00
Jason T Alborough
72477a9a24 Changes to EssentialsFramework 2019-03-06 09:06:41 -05:00
Jason T Alborough
6c02423a1c Adds DisplayControllerBRidge 2019-01-21 11:42:47 -05:00
Jason T Alborough
6ea966ec6c Adds the CameraCOntroller to the BridgeFactory 2019-01-21 11:40:48 -05:00
Jason T Alborough
6e9b24576e Fixes issue in the DmChassisControllerBRidge wher ethe Tx input sysnc was not getting properly connected. 2019-01-21 11:34:37 -05:00
Jason T Alborough
ad04235061 Adds CameraContorllerBridge 2019-01-21 10:57:11 -05:00
Jason T Alborough
34f3e543f2 Adds Display Controller base with some basic functioanlity. 2019-01-11 20:22:23 -05:00
Jason T Alborough
e145bfbaee Merge remote-tracking branch 'origin/feature/ecs-994' into JTA 2019-01-10 10:51:38 -05:00
Jason T Alborough
4f726007b8 Adds merged Essentials core 2019-01-10 10:51:18 -05:00
Jason T Alborough
d62b5b7e0c Starts DisplayControllerBridge
Starts DspControllerBridge.
Note these are not yet functional.
2019-01-10 10:49:08 -05:00
Neil Dorin
967d281b62 Includes essentials-framework commit that adds ability for a DM-RMC-4KZ-100-C to be created. 2019-01-08 14:29:53 -07:00
Jason T Alborough
be9fd5e8d1 Adds IsOnline FB to GenericLightingBridge 2019-01-03 17:27:07 -05:00
Jason T Alborough
f25d05edc2 Adds GenericLightingBridge 2019-01-02 12:52:30 -05:00
Neil Dorin
c3d6890a4c Minor updates from testing MC 2018-12-21 16:12:43 -07:00
Neil Dorin
ff6184c241 Adds AudioCodecBaseMessenger and includes updates for Audio Codec on EssentialsHuddleVtc1Room type and for use in Mobile Control 2018-12-20 17:01:34 -07:00
Neil Dorin
034c6913f7 Adds call history messages to VideoCodecBaseMessenger. Removes all call related messages from CotijaEssentialsHuddleSpaceRoomBridge 2018-12-19 16:03:08 -07:00
Joshua Gutenplan
03da699a36 pull essentials updates into vance sub mod 2018-12-18 19:07:44 -08:00
Neil Dorin
3a3f6db692 Updates to fix issues with sending individual program status messages to the app server. Minor updates to AtcDdvc01Messenger based on testing MC with Heath 2018-12-18 17:22:33 -07:00
Neil Dorin
87a449d1ee Silenced AppServer heartbeat console messages. Added isInCall property to Atc status message in AtcDdvc01Messenger SendFullStatus() 2018-12-17 16:28:19 -07:00
Jason T Alborough
1d6a835323 CHanges submodule to merged commit 2018-12-17 11:12:33 -05:00
Jason T Alborough
6bbad2e0f9 Merge remote-tracking branch 'origin/feature/ecs-967' into JTA
# Conflicts:
#	PepperDashEssentials/AppServer/CotijaSystemController.cs
#	PepperDashEssentials/Bridges/BridgeBase.cs
#	PepperDashEssentials/Bridges/IBasicCommunicationBridge.cs
#	PepperDashEssentials/PepperDashEssentials.csproj
#	Release Package/PepperDashEssentials.cpz
#	Release Package/PepperDashEssentials.dll
#	essentials-framework
2018-12-17 11:11:14 -05:00
Neil Dorin
821f2a6d60 Updates from testing System Monitor messaging with AppServer 2018-12-14 16:56:17 -07:00
Neil Dorin
f6136a8c77 Adds SystemMonitroMessenger to bridge between SystemMonitorController and AppServer (untested) 2018-12-12 16:23:17 -07:00
Neil Dorin
676526ed48 Merge remote-tracking branch 'origin/bugfix/mob-470' into feature/ecs-967
# Conflicts:
#	PepperDashEssentials/AppServer/CotijaSystemController.cs
#	PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs
#	PepperDashEssentials/ControlSystem.cs
#	PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs
#	PepperDashEssentials/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs
#	PepperDashEssentials/Properties/AssemblyInfo.cs
#	PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs
#	devjson commands.json
2018-12-12 13:34:32 -07:00
Neil Dorin
a8ffe2d09f Adds merged essentials-framework branch 2018-12-12 13:13:34 -07:00
Neil Dorin
541fbbbb2d Testing SytemMonitorBridge 2018-12-12 12:59:00 -07:00
Neil Dorin
3a5686c27a Testing SystemMonitorBridge 2018-12-11 17:58:52 -07:00
Neil Dorin
531e7186f2 Added feedback/action linking to SystemMonitorBridge 2018-12-10 16:33:24 -07:00
Neil Dorin
9bc0269e78 Updates to SystemMonitorBridge 2018-12-07 17:30:51 -07:00
Neil Dorin
0df53facb1 Starting on SystemMonitorBridge 2018-12-06 17:24:55 -07:00
Neil Dorin
2ee77f1bca Adds System Monitor program initialization feedback to startup procedure. Adds bridges for GenericRelayDevice and IDigitalInput device tyeps. 2018-12-06 14:43:38 -07:00
Jason T Alborough
9a56f5bb49 Adds control for DigitalLogger PDU Device
Adds EiscBridge for DigitalLogger PDU Device.
2018-12-03 22:47:49 -05:00
Jason T Alborough
895f49b888 Adds some DigitalLogger funcitonality and begins merge process with new Bridge concepts. 2018-12-03 12:42:17 -05:00
Neil Dorin
e51e1930d9 Minor updates to essentials-framework 2018-11-26 12:37:47 -07:00
Neil Dorin
d245f36cf3 adds framework commit 2018-11-26 11:59:28 -07:00
Neil Dorin
a7c920b780 Added Hdcp actions and feedbacks 2018-10-08 16:55:35 -06:00
Neil Dorin
3a91a895e6 Removed Cue from Feedback 2018-10-08 15:49:21 -06:00
Heath Volmer
397b0b4d9c DDVC01 bridge, repaired device controls 2018-10-08 15:17:02 -06:00
Neil Dorin
b793c04ad3 Merge branch 'bugfix/ecs-895' into feature/ecs-877
# Conflicts:
#	PepperDashEssentials/Properties/AssemblyInfo.cs
#	PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs
#	Release Package/PepperDashEssentials.cpz
#	Release Package/PepperDashEssentials.dll
2018-10-08 13:30:18 -06:00
Neil Dorin
bd31831a9b Fixes issue with TimeoutMinutes property being mispelled in EssentialsRoomConfig. Adds additional debug messages to assist with vacancy timeout testing 2018-10-08 13:18:50 -06:00
Neil Dorin
3d9070dc4f Updates to get Tx Hdcp support working 2018-10-05 17:20:07 -06:00
Neil Dorin
3f82eaeb66 Adds CEC support for all DM TX/RX and input/output cards 2018-10-04 17:00:44 -06:00
Heath Volmer
3cbf784417 Added messaging for code prompt login methods 2018-10-03 18:17:12 -06:00
Neil Dorin
3d6ce7534f Adds Edid and video resolution support for Dm Rmc over EiscApi bridge. Beginnings of Cec control 2018-10-03 17:49:08 -06:00
Heath Volmer
28d694d0b4 Reset of connected simpl program will no longer add duplicate audioCodec and videoCodec devices to output config 2018-10-02 13:02:46 -06:00
Neil Dorin
a320eff13c Updated join map to fix issue with audio/video source selection and feedback 2018-10-01 19:34:53 -06:00
Neil Dorin
f7db0ef36c Working on implementing video and audio source control/feedback for TXs 2018-09-28 17:08:21 -06:00
Heath Volmer
184144dc3c Touchups to ddvc mob codec messages 2018-09-27 17:50:04 -06:00
Neil Dorin
dfd7cb4411 Adds DmTxControllerBridge 2018-09-27 17:27:35 -06:00
Heath Volmer
5014343fa3 DDVC01 - MOB ATC messaging changes 2018-09-27 10:50:23 -06:00
Neil Dorin
f2bfeda074 Tested DmChassisController over EiscApi bridge. So far, no issues found 2018-09-26 16:09:43 -06:00
Neil Dorin
339a4f8a62 Adds DmChassicControllerBridge. Created JoinMapBase base class 2018-09-25 17:19:53 -06:00
Heath Volmer
78668e8abb Added config construction for audio conf in DDVC MOB bridge 2018-09-25 14:36:38 -06:00
Heath Volmer
101d1b5625 Added handler for phone call activity, DDVC bridge 2018-09-24 15:01:02 -06:00
Neil Dorin
780f7bc249 Added joinmap for IBasicCommunication and testet Com, Tcp, Ssh 2018-09-24 10:39:55 -06:00
Neil Dorin
6ec0295aba Progress on comm bridge 2018-09-20 17:13:54 -06:00
Neil Dorin
f4d2ad86f5 fixes ecs-861. Wrong event was being registered on GlsOccupancySensorBase 2018-09-20 15:48:23 -06:00
Neil Dorin
d98b7e837a Commit before switching branches 2018-09-20 14:14:59 -06:00
Heath Volmer
99da6debdc Switched Websocket to synchronous Send method. Seems to prevent data loss 2018-09-19 11:46:52 -06:00
Neil Dorin
c2665f0225 Added first set of interface extension methods for linking devices to EISC sigs 2018-09-18 17:54:45 -06:00
Neil Dorin
0406361d75 Updates from testing UI reconnecting to room after room properties update from Fusion 2018-09-18 17:53:33 -06:00
Neil Dorin
182326b3c5 Updated EssentialsRoomBase and both extented types to use ReconfigurableDevice. Tested Fusion Custom Properties successfully updating room name and help message. 2018-09-14 21:26:25 -06:00
Jason T Alborough
4a69207038 ECS-838 Add method to set lighting integrationID from Bridge. 2018-09-14 16:55:22 -04:00
Jason T Alborough
7b4aad3516 Modifications to EssentialsDsp Bridge
As installed in Wharton HH.8th floor 2018-09-14
2018-09-14 09:12:47 -04:00
Neil Dorin
8dabe732ec Renamed Config in Essentials room type classes to PropertiesConfig and modified EssentialsRoomBase to derive from ReconfigurableDevice 2018-09-13 16:50:08 -06:00
Jason T Alborough
410cf1b4ad ECS-839 Add autoAnswer Support to QscDialer and Bridge
ECS-836 Add DigitalLogger PowerController to Devices with Temp Bridge. This is just stared. Not yet complete
2018-09-12 18:54:33 -04:00
Neil Dorin
fbb4951548 Merged in feature/ecs-829 (pull request #3)
Feature/ecs 829

Approved-by: HeathV <hvolmer@ddsys.co>
2018-09-12 20:11:38 +00:00
Neil Dorin
065075aabd Fixed issue with creating events in edge scenarios when properties change from Fusion 2018-09-12 13:57:15 -06:00
Heath Volmer
ee6293fa75 Added MessengerBase class to app server stuff 2018-09-12 13:53:35 -06:00
Neil Dorin
7112c50f5a Adds Fusion Custom Properties support and bridge to pass values from custom properties to devices 2018-09-11 19:36:10 -06:00
Heath Volmer
873fd81b5c Added debug command to log marker in log 2018-09-11 10:04:41 -06:00
Heath Volmer
a2a3f4caed Clean up extra verbose logging after solidifying reconnection 2018-09-11 08:13:14 -06:00
Heath Volmer
1df658b7eb Added close handlers to catch legit shutdowns from servers 2018-09-10 20:23:57 -06:00
Heath Volmer
1c9061cc28 Strengthened reconnect behavior with both app server and IIS outages 2018-09-10 13:49:56 -06:00
Heath Volmer
a0a83a1af7 Removed HTTP join procedure; rehashed reconnects 2018-09-10 13:00:03 -06:00
Heath Volmer
f17b62844d Attempting to prevent deadlock/multiple connection attempts on reconnect 2018-09-10 07:48:14 -06:00
Heath Volmer
5f8170fb66 Commit of framework 2018-09-07 18:15:39 -06:00
Heath Volmer
42086f650d Weil-related changes; app server, many websocket and http client related changes to imrpove connection resilience; Added newer pd.core 1.0.9 2018-09-07 18:09:59 -06:00
Neil Dorin
6a8ae5b244 Fixes bug that caused exceptions in Fusion GetProcessorEthernetValues() when ethernet link status came up. Adds logic for Fusion custom properties. 2018-09-07 16:01:23 -06:00
Neil Dorin
30506419df Moved config reader/writer classes to essentials core. refactored as a result 2018-09-07 15:58:03 -06:00
Jason T Alborough
a84084b273 Adds Online to EssentialsDsp 2018-09-06 20:08:00 -04:00
Heath Volmer
5ed8ff6dac Fixed scope issue joining sources to EISC 2018-09-04 15:39:58 -06:00
Heath Volmer
b295f931a3 ? 2018-09-04 14:31:29 -06:00
Neil Dorin
0487099ee4 Added logic to read local config if found, instead of Portal config by default 2018-09-04 14:28:16 -06:00
Jason T Alborough
bff8529c9f Changes to QscDialer 2018-09-03 15:33:13 -04:00
Neil Dorin
c3bea683fc Added ConfigWriter class. Updated AV Funciton Driver UI classes to show shutdown prompt when room about to shut down for vacancy. 2018-08-31 18:06:43 -06:00
Jason T Alborough
f819d0d743 QscAtc Work form live test at Wharton HH.830. Needs more vetting. 2018-08-29 17:32:23 -04:00
Neil Dorin
6afe1729bf Updated UI drivers to make sure modal shutdown warning is shown when vacancy shutdown is triggered 2018-08-29 11:56:41 -06:00
Neil Dorin
d563a6224b sub module updates 2018-08-28 17:03:38 -06:00
Neil Dorin
7ba2429cbf Updates from bench testing RoomOnToDefaultSourceWhenOccupied. Now tested and working using config file values. 2018-08-28 17:03:07 -06:00
Jason T Alborough
1534433949 Ecs-823 Implement Essentials Light Bridge
WHAR-1441 Add Lutron Temp Bridge
WHAR-1401 Finish testing Lighting Controls
2018-08-27 17:24:53 -04:00
Jason T Alborough
daf44ae797 Started the EssentialsLightBridge class 2018-08-25 07:28:40 -04:00
Neil Dorin
bd31d76e8b New Room on to default source feature working using scheduled events and built in scheduler based on config values 2018-08-24 18:08:25 -06:00
Jason T Alborough
759635b364 WHAR-1436 - Add Vol control up/down buttons on the user page 2018-08-24 14:12:53 -04:00
Neil Dorin
c0c90f926e Updates to add necessary functionality for occupancy sensors to trigger room to power on to default source during specific hours on certain days. 2018-08-21 18:23:31 -06:00
Jason T Alborough
96e60f6eaf Adds Hdcp Support for Tx30X and Tx201 2018-08-15 18:38:21 -04:00
Jason T Alborough
a13428fb4e Commented out a read-only property. Merge Issue mabey 2018-08-14 09:45:41 -04:00
Jason T Alborough
818d6c9ca5 Adds HdcpSupport for Tx to EssentialsDM Bridge 2018-08-14 09:44:50 -04:00
Jason T Alborough
a6df8f908b Merge branch 'development' into JTAChanges
# Conflicts:
#	essentials-framework
2018-08-13 14:51:55 -04:00
Jason T Alborough
0d5c93bbde WHAR-1397 Removes extraneous debug traces 2018-08-13 13:51:23 -04:00
Jason T Alborough
40dcca0e8d Minor changes for HDCP support. Not yet complete. 2018-08-10 18:56:09 -04:00
Jason T Alborough
ef443bdfb0 Created a device for TVOneCorio with online status and preset recall/FB
Created a temp bridge for EiscApi
2018-08-10 12:29:15 -04:00
Heath Volmer
c839cea495 Added JSON property converter to sourceListItem type; commands to start room from call button 2018-08-09 16:46:05 -06:00
Heath Volmer
768bbf9298 Initial implmentation of directory search 2018-08-08 17:35:21 -06:00
Heath Volmer
999982f789 Restructured directory message 2018-08-08 11:19:39 -06:00
Heath Volmer
ad48b1ebac Added starter method for directory root:good; adding json props and converters to directory classes 2018-08-08 10:34:40 -06:00
Heath Volmer
e196ff1627 Adding VTC device messaging; full status; isReady check 2018-08-06 17:19:45 -06:00
Jason T Alborough
a900a08095 Merge branch 'Feature/QSC' of https://bitbucket.org/Pepperdash_Products/essentials into Feature/QSC 2018-08-06 11:29:06 -04:00
Jason T Alborough
fa94b83d63 Changes from Staging HH.8 2018-08-06 11:28:00 -04:00
Heath Volmer
d70d8b58dd Added new Messenger for video codec 2018-08-03 16:42:36 -06:00
Heath Volmer
1b942918d7 Moved cotija classes into appserver folder; adding VideoCodecBaseMessenger class 2018-08-03 15:50:20 -06:00
Heath Volmer
ccfcd95508 Added codec dial and end commands 2018-08-03 14:17:45 -06:00
Alex Johnson
5f119690c2 Commit for essentials-framework submodule update 2018-08-03 10:23:52 -04:00
Heath Volmer
3778314d51 Added messages for share state to essentials MC bridge 2018-08-02 17:06:10 -06:00
Heath Volmer
163f6e6941 Various cleanup; added messaging for codec status events; added initial state of codec to fullstatus message 2018-08-01 16:59:09 -06:00
Heath Volmer
7e8cdd738f Fixed where system won't register if no uuid in config (from manual config) 2018-08-01 15:30:10 -06:00
Heath Volmer
1371c728c5 Merge and a whole bunch of work before committing merge, moron 2018-08-01 14:23:58 -06:00
Heath Volmer
d1d8e29be2 Preparing essentials message changes, noticed that 754 has not been merged 2018-08-01 11:38:39 -06:00
Alex Johnson
43071a4d91 Recommit 2018-07-31 17:20:03 -04:00
Alex Johnson
4d4d50bc92 Update to framework submodule for Tx and Rx dictionary creation 2018-07-31 17:17:14 -04:00
Heath Volmer
9eb9485bba Recommit after merging framework sub 2018-07-27 07:36:09 -06:00
Heath Volmer
c447875baf post conflict resolution 2018-07-25 11:01:10 -06:00
Neil Dorin
f1feaaae90 Merged in bugfix/ecs-756 (pull request #1)
Bugfix/ecs 756
2018-07-25 16:54:14 +00:00
Neil Dorin
b989b07d78 Updates as per Heath to volumes object in SendFullStatus(). Fixed issue with populating SourceDeviceMapDictionary in constructor. 2018-07-24 15:11:48 -06:00
Heath Volmer
3841a9bad1 Added power-on semaphore to Sammy display to prevent power on glitches 2018-07-20 15:44:59 -06:00
Neil Dorin
9ad2fef94a Updates as per request from Heath 2018-07-19 17:04:23 -06:00
Neil Dorin
f09ccda33c sub-module updates 2018-07-19 11:16:27 -06:00
Neil Dorin
4e45103080 resolves ecs-797/770/755 Updates Interface extension classes and SourceDeviceMapDictionary to us consistent names 2018-07-19 11:16:09 -06:00
Neil Dorin
c2e82e9cb9 Commit framework changes 2018-07-18 15:04:57 -06:00
Neil Dorin
b16d61f64c Updatest to CotjaDdvc01RoomBridge to enable source control joins on EISC (need to update API words in dictionary to match existing interface extensions) 2018-07-18 15:04:39 -06:00
Jason T Alborough
2e566b41a0 Removed release cpz for script compatibility. 2018-07-18 16:07:45 -04:00
Jason T Alborough
be5b23e9d1 Qsc and EssentialsDspBridge with Functional vol, mute, and preset control...still needs more work though 2018-07-18 12:13:35 -04:00
Neil Dorin
385686e7e0 Added Bridge classes back in from on prem repo 2018-07-17 11:32:38 -06:00
Jason T Alborough
448b408f94 Merges Essentials bridges proof of concept work into new BB.org repo 2018-07-17 08:05:02 -04:00
Jason T Alborough
e1422d8653 Changes essentials-framework branch to essentialsBridges 2018-07-17 07:12:49 -04:00
Jason T Alborough
b353b93458 Adds essentials-framework commit 2018-07-16 19:50:34 -04:00
Jason T Alborough
55f9dc4c1f .gitmodules removed @ in URL
.gitmodules removed @ in URL
2018-07-16 19:49:45 -04:00
Neil Dorin
e7adaabb87 Fixed .gitmodules to use URL withouth hvolmer prefix 2018-07-16 15:06:43 -06:00
Neil Dorin
0f25d9ed4b include updates to essentials-framework 2018-07-12 16:56:12 -06:00
Neil Dorin
5cefba4934 Brings in changes from On Prem BB repo. Resolves ecs-756/757/758/759 2018-07-12 16:55:49 -06:00
93 changed files with 12498 additions and 8813 deletions

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "essentials-framework"]
path = essentials-framework
url = https://hvolmer@bitbucket.org/Pepperdash_Products/essentials-framework.git
url = https://bitbucket.org/Pepperdash_Products/essentials-framework.git

View File

@@ -1,49 +1,49 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDashEssentials", ".\PepperDashEssentials\PepperDashEssentials.csproj", "{1BED5BA9-88C4-4365-9362-6F4B128071D3}"
ProjectSection(ProjectDependencies) = postProject
{892B761C-E479-44CE-BD74-243E9214AF13} = {892B761C-E479-44CE-BD74-243E9214AF13}
{9199CE8A-0C9F-4952-8672-3EED798B284F} = {9199CE8A-0C9F-4952-8672-3EED798B284F}
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Essentials_Core", ".\essentials-framework\Essentials Core\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj", "{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials Devices Common", ".\essentials-framework\Essentials Devices Common\Essentials Devices Common\Essentials Devices Common.csproj", "{892B761C-E479-44CE-BD74-243E9214AF13}"
ProjectSection(ProjectDependencies) = postProject
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials_DM", ".\essentials-framework\Essentials DM\Essentials_DM\Essentials_DM.csproj", "{9199CE8A-0C9F-4952-8672-3EED798B284F}"
ProjectSection(ProjectDependencies) = postProject
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.Build.0 = Release|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.Build.0 = Release|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.Build.0 = Release|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDashEssentials", ".\PepperDashEssentials\PepperDashEssentials.csproj", "{1BED5BA9-88C4-4365-9362-6F4B128071D3}"
ProjectSection(ProjectDependencies) = postProject
{892B761C-E479-44CE-BD74-243E9214AF13} = {892B761C-E479-44CE-BD74-243E9214AF13}
{9199CE8A-0C9F-4952-8672-3EED798B284F} = {9199CE8A-0C9F-4952-8672-3EED798B284F}
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Essentials_Core", ".\essentials-framework\Essentials Core\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj", "{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials Devices Common", ".\essentials-framework\Essentials Devices Common\Essentials Devices Common\Essentials Devices Common.csproj", "{892B761C-E479-44CE-BD74-243E9214AF13}"
ProjectSection(ProjectDependencies) = postProject
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials_DM", ".\essentials-framework\Essentials DM\Essentials_DM\Essentials_DM.csproj", "{9199CE8A-0C9F-4952-8672-3EED798B284F}"
ProjectSection(ProjectDependencies) = postProject
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5} = {A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BED5BA9-88C4-4365-9362-6F4B128071D3}.Release|Any CPU.Build.0 = Release|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}.Release|Any CPU.Build.0 = Release|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{892B761C-E479-44CE-BD74-243E9214AF13}.Release|Any CPU.Build.0 = Release|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9199CE8A-0C9F-4952-8672-3EED798B284F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -14,9 +14,9 @@ namespace PepperDash.Essentials.Room.Cotija
{
var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key);
controller.AddAction(prefix + "chanup", new PressAndHoldAction(dev.ChannelUp));
controller.AddAction(prefix + "chandown", new PressAndHoldAction(dev.ChannelDown));
controller.AddAction(prefix + "lastchan", new PressAndHoldAction(dev.LastChannel));
controller.AddAction(prefix + "chanUp", new PressAndHoldAction(dev.ChannelUp));
controller.AddAction(prefix + "chanDown", new PressAndHoldAction(dev.ChannelDown));
controller.AddAction(prefix + "lastChan", new PressAndHoldAction(dev.LastChannel));
controller.AddAction(prefix + "guide", new PressAndHoldAction(dev.Guide));
controller.AddAction(prefix + "info", new PressAndHoldAction(dev.Info));
controller.AddAction(prefix + "exit", new PressAndHoldAction(dev.Exit));
@@ -26,9 +26,9 @@ namespace PepperDash.Essentials.Room.Cotija
{
var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key);
controller.RemoveAction(prefix + "chanup");
controller.RemoveAction(prefix + "chandown");
controller.RemoveAction(prefix + "lastchan");
controller.RemoveAction(prefix + "chanUp");
controller.RemoveAction(prefix + "chanDown");
controller.RemoveAction(prefix + "lastChan");
controller.RemoveAction(prefix + "guide");
controller.RemoveAction(prefix + "info");
controller.RemoveAction(prefix + "exit");

View File

@@ -24,8 +24,8 @@ namespace PepperDash.Essentials.Room.Cotija
controller.AddAction(prefix + "num7", new PressAndHoldAction(dev.Digit0));
controller.AddAction(prefix + "num8", new PressAndHoldAction(dev.Digit0));
controller.AddAction(prefix + "num9", new PressAndHoldAction(dev.Digit0));
controller.AddAction(prefix + "dash", new PressAndHoldAction(dev.KeypadAccessoryButton1));
controller.AddAction(prefix + "enter", new PressAndHoldAction(dev.KeypadAccessoryButton2));
controller.AddAction(prefix + "numDash", new PressAndHoldAction(dev.KeypadAccessoryButton1));
controller.AddAction(prefix + "numEnter", new PressAndHoldAction(dev.KeypadAccessoryButton2));
// Deal with the Accessory functions on the numpad later
}
@@ -43,8 +43,8 @@ namespace PepperDash.Essentials.Room.Cotija
controller.RemoveAction(prefix + "num7");
controller.RemoveAction(prefix + "num8");
controller.RemoveAction(prefix + "num9");
controller.RemoveAction(prefix + "dash");
controller.RemoveAction(prefix + "enter");
controller.RemoveAction(prefix + "numDash");
controller.RemoveAction(prefix + "numEnter");
}
}
}

View File

@@ -14,18 +14,18 @@ namespace PepperDash.Essentials.Room.Cotija
{
var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key);
controller.AddAction(prefix + "poweron", new Action(dev.PowerOn));
controller.AddAction(prefix + "poweroff", new Action(dev.PowerOff));
controller.AddAction(prefix + "powertoggle", new Action(dev.PowerToggle));
controller.AddAction(prefix + "powerOn", new Action(dev.PowerOn));
controller.AddAction(prefix + "powerOff", new Action(dev.PowerOff));
controller.AddAction(prefix + "powerToggle", new Action(dev.PowerToggle));
}
public static void UnlinkActions(this IPower dev, CotijaSystemController controller)
{
var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key);
controller.RemoveAction(prefix + "poweron");
controller.RemoveAction(prefix + "poweroff");
controller.RemoveAction(prefix + "powertoggle");
controller.RemoveAction(prefix + "powerOn");
controller.RemoveAction(prefix + "powerOff");
controller.RemoveAction(prefix + "powerToggle");
}
}

View File

@@ -14,7 +14,7 @@ namespace PepperDash.Essentials.Room.Cotija
{
var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key);
controller.AddAction(prefix + "dvrlist", new PressAndHoldAction(dev.DvrList));
controller.AddAction(prefix + "dvrList", new PressAndHoldAction(dev.DvrList));
controller.AddAction(prefix + "replay", new PressAndHoldAction(dev.Replay));
}
@@ -22,7 +22,7 @@ namespace PepperDash.Essentials.Room.Cotija
{
var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key);
controller.RemoveAction(prefix + "dvrlist");
controller.RemoveAction(prefix + "dvrList");
controller.RemoveAction(prefix + "replay");
}
}

View File

@@ -17,8 +17,8 @@ namespace PepperDash.Essentials.Room.Cotija
controller.AddAction(prefix + "play", new PressAndHoldAction(dev.Play));
controller.AddAction(prefix + "pause", new PressAndHoldAction(dev.Pause));
controller.AddAction(prefix + "stop", new PressAndHoldAction(dev.Stop));
controller.AddAction(prefix + "prevtrack", new PressAndHoldAction(dev.ChapPlus));
controller.AddAction(prefix + "nexttrack", new PressAndHoldAction(dev.ChapMinus));
controller.AddAction(prefix + "prevTrack", new PressAndHoldAction(dev.ChapPlus));
controller.AddAction(prefix + "nextTrack", new PressAndHoldAction(dev.ChapMinus));
controller.AddAction(prefix + "rewind", new PressAndHoldAction(dev.Rewind));
controller.AddAction(prefix + "ffwd", new PressAndHoldAction(dev.FFwd));
controller.AddAction(prefix + "record", new PressAndHoldAction(dev.Record));
@@ -31,8 +31,8 @@ namespace PepperDash.Essentials.Room.Cotija
controller.RemoveAction(prefix + "play");
controller.RemoveAction(prefix + "pause");
controller.RemoveAction(prefix + "stop");
controller.RemoveAction(prefix + "prevtrack");
controller.RemoveAction(prefix + "nexttrack");
controller.RemoveAction(prefix + "prevTrack");
controller.RemoveAction(prefix + "nextTrack");
controller.RemoveAction(prefix + "rewind");
controller.RemoveAction(prefix + "ffwd");
controller.RemoveAction(prefix + "record");

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.Cotija
{
/// <summary>
/// Represents a room whose configuration is derived from runtime data,
/// perhaps from another program, and that the data may not be fully
/// available at startup.
/// </summary>
public interface IDelayedConfiguration
{
event EventHandler<EventArgs> ConfigurationIsReady;
}
}
namespace PepperDash.Essentials
{
/// <summary>
/// For rooms with a single presentation source, change event
/// </summary>
public interface IHasCurrentSourceInfoChange
{
string CurrentSourceInfoKey { get; }
SourceListItem CurrentSourceInfo { get; }
event SourceInfoChangeHandler CurrentSingleSourceChange;
}
/// <summary>
/// For rooms with routing
/// </summary>
public interface IRunRouteAction
{
void RunRouteAction(string routeKey);
void RunRouteAction(string routeKey, Action successCallback);
}
/// <summary>
/// For rooms that default presentation only routing
/// </summary>
public interface IRunDefaultPresentRoute
{
bool RunDefaultPresentRoute();
}
/// <summary>
/// For rooms that have default presentation and calling routes
/// </summary>
public interface IRunDefaultCallRoute : IRunDefaultPresentRoute
{
bool RunDefaultCallRoute();
}
}

View File

@@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.EthernetCommunication;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Codec;
namespace PepperDash.Essentials.AppServer.Messengers
{
public class Ddvc01AtcMessenger : MessengerBase
{
BasicTriList EISC;
const uint BDialHangup = 221;
const uint BIncomingAnswer = 251;
const uint BIncomingReject = 252;
const uint BSpeedDial1 = 241;
const uint BSpeedDial2 = 242;
const uint BSpeedDial3 = 243;
const uint BSpeedDial4 = 244;
/// <summary>
/// 201
/// </summary>
const uint SCurrentDialString = 201;
/// <summary>
/// 211
/// </summary>
const uint SCurrentCallNumber = 211;
/// <summary>
/// 212
/// </summary>
const uint SCurrentCallName = 212;
/// <summary>
/// 221
/// </summary>
const uint SHookState = 221;
/// <summary>
/// 222
/// </summary>
const uint SCallDirection = 222;
/// <summary>
///
/// </summary>
Dictionary<string, uint> DTMFMap = new Dictionary<string, uint>
{
{ "1", 201 },
{ "2", 202 },
{ "3", 203 },
{ "4", 204 },
{ "5", 205 },
{ "6", 206 },
{ "7", 207 },
{ "8", 208 },
{ "9", 209 },
{ "0", 210 },
{ "*", 211 },
{ "#", 212 },
};
CodecActiveCallItem CurrentCallItem;
/// <summary>
///
/// </summary>
/// <param name="eisc"></param>
/// <param name="messagePath"></param>
public Ddvc01AtcMessenger(string key, BasicTriList eisc, string messagePath)
: base(key, messagePath)
{
EISC = eisc;
CurrentCallItem = new CodecActiveCallItem();
CurrentCallItem.Type = eCodecCallType.Audio;
CurrentCallItem.Id = "-audio-";
}
/// <summary>
///
/// </summary>
void SendFullStatus()
{
this.PostStatusMessage(new
{
calls = GetCurrentCallList(),
currentCallString = EISC.GetString(SCurrentCallNumber),
currentDialString = EISC.GetString(SCurrentDialString),
isInCall = EISC.GetString(SHookState) == "Connected"
});
}
/// <summary>
///
/// </summary>
/// <param name="appServerController"></param>
protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController)
{
//EISC.SetStringSigAction(SCurrentDialString, s => PostStatusMessage(new { currentDialString = s }));
EISC.SetStringSigAction(SHookState, s =>
{
CurrentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true);
//GetCurrentCallList();
SendCallsList();
});
EISC.SetStringSigAction(SCurrentCallNumber, s =>
{
CurrentCallItem.Number = s;
SendCallsList();
});
EISC.SetStringSigAction(SCurrentCallName, s =>
{
CurrentCallItem.Name = s;
SendCallsList();
});
EISC.SetStringSigAction(SCallDirection, s =>
{
CurrentCallItem.Direction = (eCodecCallDirection)Enum.Parse(typeof(eCodecCallDirection), s, true);
SendCallsList();
});
// Add press and holds using helper
Action<string, uint> addPHAction = (s, u) =>
AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b)));
// Add straight pulse calls
Action<string, uint> addAction = (s, u) =>
AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100)));
addAction("/endCallById", BDialHangup);
addAction("/acceptById", BIncomingAnswer);
addAction("/rejectById", BIncomingReject);
addAction("/speedDial1", BSpeedDial1);
addAction("/speedDial2", BSpeedDial2);
addAction("/speedDial3", BSpeedDial3);
addAction("/speedDial4", BSpeedDial4);
// Get status
AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus));
// Dial on string
AppServerController.AddAction(MessagePath + "/dial", new Action<string>(s => EISC.SetString(SCurrentDialString, s)));
// Pulse DTMF
AppServerController.AddAction(MessagePath + "/dtmf", new Action<string>(s =>
{
if (DTMFMap.ContainsKey(s))
{
EISC.PulseBool(DTMFMap[s], 100);
}
}));
}
void SendCallsList()
{
PostStatusMessage(new
{
calls = GetCurrentCallList(),
});
}
/// <summary>
/// Turns the
/// </summary>
/// <returns></returns>
List<CodecActiveCallItem> GetCurrentCallList()
{
if (CurrentCallItem.Status == eCodecCallStatus.Disconnected)
{
return new List<CodecActiveCallItem>();
}
else
{
return new List<CodecActiveCallItem>() { CurrentCallItem };
}
}
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides a messaging bridge for an AudioCodecBase device
/// </summary>
public class AudioCodecBaseMessenger : MessengerBase
{
/// <summary>
/// Device being bridged
/// </summary>
public AudioCodecBase Codec { get; set; }
/// <summary>
/// Constuctor
/// </summary>
/// <param name="key"></param>
/// <param name="codec"></param>
/// <param name="messagePath"></param>
public AudioCodecBaseMessenger(string key, AudioCodecBase codec, string messagePath)
: base(key, messagePath)
{
if (codec == null)
throw new ArgumentNullException("codec");
Codec = codec;
codec.CallStatusChange += new EventHandler<CodecCallStatusItemChangeEventArgs>(codec_CallStatusChange);
}
protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController)
{
appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendAtcFullMessageObject));
appServerController.AddAction(MessagePath + "/dial", new Action<string>(s => Codec.Dial(s)));
appServerController.AddAction(MessagePath + "/endCallById", new Action<string>(s =>
{
var call = GetCallWithId(s);
if (call != null)
Codec.EndCall(call);
}));
appServerController.AddAction(MessagePath + "/endAllCalls", new Action(Codec.EndAllCalls));
appServerController.AddAction(MessagePath + "/dtmf", new Action<string>(s => Codec.SendDtmf(s)));
appServerController.AddAction(MessagePath + "/rejectById", new Action<string>(s =>
{
var call = GetCallWithId(s);
if (call != null)
Codec.RejectCall(call);
}));
appServerController.AddAction(MessagePath + "/acceptById", new Action<string>(s =>
{
var call = GetCallWithId(s);
if (call != null)
Codec.AcceptCall(call);
}));
}
/// <summary>
/// Helper to grab a call with string ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
CodecActiveCallItem GetCallWithId(string id)
{
return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id);
}
void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
SendAtcFullMessageObject();
}
/// <summary>
/// Helper method to build call status for vtc
/// </summary>
/// <returns></returns>
void SendAtcFullMessageObject()
{
var info = Codec.CodecInfo;
PostStatusMessage(new
{
isInCall = Codec.IsInCall,
calls = Codec.ActiveCalls,
info = new
{
phoneNumber = info.PhoneNumber
}
});
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides a messaging bridge for a VideoCodecBase
/// </summary>
public abstract class MessengerBase : IKeyed
{
public string Key { get; private set; }
/// <summary>
///
/// </summary>
public CotijaSystemController AppServerController { get; private set; }
public string MessagePath { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="codec"></param>
public MessengerBase(string key, string messagePath)
{
Key = key;
if (string.IsNullOrEmpty(messagePath))
throw new ArgumentException("messagePath must not be empty or null");
MessagePath = messagePath;
}
/// <summary>
/// Registers this messenger with appserver controller
/// </summary>
/// <param name="appServerController"></param>
public void RegisterWithAppServer(CotijaSystemController appServerController)
{
if (appServerController == null)
throw new ArgumentNullException("appServerController");
AppServerController = appServerController;
CustomRegisterWithAppServer(AppServerController);
}
/// <summary>
/// Implemented in extending classes. Wire up API calls and feedback here
/// </summary>
/// <param name="appServerController"></param>
abstract protected void CustomRegisterWithAppServer(CotijaSystemController appServerController);
/// <summary>
/// Helper for posting status message
/// </summary>
/// <param name="contentObject">The contents of the content object</param>
protected void PostStatusMessage(object contentObject)
{
if (AppServerController != null)
{
AppServerController.SendMessageToServer(JObject.FromObject(new
{
type = MessagePath,
content = contentObject
}));
}
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Monitoring;
namespace PepperDash.Essentials.AppServer.Messengers
{
public class SystemMonitorMessenger : MessengerBase
{
public SystemMonitorController SysMon { get; private set; }
public SystemMonitorMessenger(string key, SystemMonitorController sysMon, string messagePath)
: base(key, messagePath)
{
if (sysMon == null)
throw new ArgumentNullException("sysMon");
SysMon = sysMon;
SysMon.SystemMonitorPropertiesChanged += new EventHandler<EventArgs>(SysMon_SystemMonitorPropertiesChanged);
foreach (var p in SysMon.ProgramStatusFeedbackCollection)
{
p.Value.ProgramInfoChanged += new EventHandler<ProgramInfoEventArgs>(ProgramInfoChanged);
}
CrestronConsole.AddNewConsoleCommand(s => SendFullStatusMessage(), "SendFullSysMonStatus", "Sends the full System Monitor Status", ConsoleAccessLevelEnum.AccessOperator);
}
/// <summary>
/// Posts the program information message
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ProgramInfoChanged(object sender, ProgramInfoEventArgs e)
{
Debug.Console(1, "Posting Status Message: {0}", e.ProgramInfo.ToString());
PostStatusMessage(e.ProgramInfo);
}
/// <summary>
/// Posts the system monitor properties
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SysMon_SystemMonitorPropertiesChanged(object sender, EventArgs e)
{
SendSystemMonitorStatusMessage();
}
void SendFullStatusMessage()
{
SendSystemMonitorStatusMessage();
foreach (var p in SysMon.ProgramStatusFeedbackCollection)
{
PostStatusMessage(p.Value.ProgramInfo);
}
}
void SendSystemMonitorStatusMessage()
{
Debug.Console(1, "Posting System Monitor Status Message.");
// This takes a while, launch a new thread
CrestronInvoke.BeginInvoke((o) =>
{
PostStatusMessage(new
{
timeZone = SysMon.TimeZoneFeedback.IntValue,
timeZoneName = SysMon.TimeZoneTextFeedback.StringValue,
ioControllerVersion = SysMon.IOControllerVersionFeedback.StringValue,
snmpVersion = SysMon.SnmpVersionFeedback.StringValue,
bacnetVersion = SysMon.BACnetAppVersionFeedback.StringValue,
controllerVersion = SysMon.ControllerVersionFeedback.StringValue
});
});
}
protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController)
{
AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatusMessage));
}
}
}

View File

@@ -0,0 +1,279 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides a messaging bridge for a VideoCodecBase device
/// </summary>
public class VideoCodecBaseMessenger : MessengerBase
{
/// <summary>
///
/// </summary>
public VideoCodecBase Codec { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="codec"></param>
public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messagePath)
: base(key, messagePath)
{
if (codec == null)
throw new ArgumentNullException("codec");
Codec = codec;
codec.CallStatusChange += new EventHandler<CodecCallStatusItemChangeEventArgs>(codec_CallStatusChange);
codec.IsReadyChange += new EventHandler<EventArgs>(codec_IsReadyChange);
var dirCodec = codec as IHasDirectory;
if (dirCodec != null)
{
dirCodec.DirectoryResultReturned += new EventHandler<DirectoryEventArgs>(dirCodec_DirectoryResultReturned);
}
var recCodec = codec as IHasCallHistory;
if (recCodec != null)
{
recCodec.CallHistory.RecentCallsListHasChanged += new EventHandler<EventArgs>(CallHistory_RecentCallsListHasChanged);
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e)
{
var recents = (sender as CodecCallHistory).RecentCalls;
if (recents != null)
{
PostStatusMessage(new
{
recentCalls = recents
});
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void dirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e)
{
PostStatusMessage(new
{
currentDirectory = e.Directory
});
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void codec_IsReadyChange(object sender, EventArgs e)
{
PostStatusMessage(new
{
isReady = true
});
}
/// <summary>
/// Called from base's RegisterWithAppServer method
/// </summary>
/// <param name="appServerController"></param>
protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController)
{
appServerController.AddAction("/device/videoCodec/isReady", new Action(SendIsReady));
appServerController.AddAction("/device/videoCodec/fullStatus", new Action(SendVtcFullMessageObject));
appServerController.AddAction("/device/videoCodec/dial", new Action<string>(s => Codec.Dial(s)));
appServerController.AddAction("/device/videoCodec/endCallById", new Action<string>(s =>
{
var call = GetCallWithId(s);
if (call != null)
Codec.EndCall(call);
}));
appServerController.AddAction(MessagePath + "/endAllCalls", new Action(Codec.EndAllCalls));
appServerController.AddAction(MessagePath + "/dtmf", new Action<string>(s => Codec.SendDtmf(s)));
appServerController.AddAction(MessagePath + "/rejectById", new Action<string>(s =>
{
var call = GetCallWithId(s);
if (call != null)
Codec.RejectCall(call);
}));
appServerController.AddAction(MessagePath + "/acceptById", new Action<string>(s =>
{
var call = GetCallWithId(s);
if (call != null)
Codec.AcceptCall(call);
}));
appServerController.AddAction(MessagePath + "/directoryRoot", new Action(GetDirectoryRoot));
appServerController.AddAction(MessagePath + "/directoryById", new Action<string>(s => GetDirectory(s)));
appServerController.AddAction(MessagePath + "/directorySearch", new Action<string>(s => DirectorySearch(s)));
appServerController.AddAction(MessagePath + "/getCallHistory", new Action(GetCallHistory));
appServerController.AddAction(MessagePath + "/privacyModeOn", new Action(Codec.PrivacyModeOn));
appServerController.AddAction(MessagePath + "/privacyModeOff", new Action(Codec.PrivacyModeOff));
appServerController.AddAction(MessagePath + "/privacyModeToggle", new Action(Codec.PrivacyModeToggle));
appServerController.AddAction(MessagePath + "/sharingStart", new Action(Codec.StartSharing));
appServerController.AddAction(MessagePath + "/sharingStop", new Action(Codec.StopSharing));
appServerController.AddAction(MessagePath + "/standbyOn", new Action(Codec.StandbyActivate));
appServerController.AddAction(MessagePath + "/standbyOff", new Action(Codec.StandbyDeactivate));
}
void GetCallHistory()
{
var codec = (Codec as IHasCallHistory);
if (codec != null)
{
var recents = codec.CallHistory.RecentCalls;
if (recents != null)
{
PostStatusMessage(new
{
recentCalls = recents
});
}
}
}
public void GetFullStatusMessage()
{
}
/// <summary>
/// Helper to grab a call with string ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
CodecActiveCallItem GetCallWithId(string id)
{
return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id);
}
/// <summary>
///
/// </summary>
/// <param name="s"></param>
void DirectorySearch(string s)
{
var dirCodec = Codec as IHasDirectory;
if (dirCodec != null)
{
dirCodec.SearchDirectory(s);
}
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
void GetDirectory(string id)
{
var dirCodec = Codec as IHasDirectory;
if(dirCodec == null)
{
return;
}
dirCodec.GetDirectoryFolderContents(id);
}
/// <summary>
///
/// </summary>
void GetDirectoryRoot()
{
var dirCodec = Codec as IHasDirectory;
if (dirCodec == null)
{
// do something else?
return;
}
if (!dirCodec.PhonebookSyncState.InitialSyncComplete)
{
PostStatusMessage(new
{
initialSyncComplete = false
});
return;
}
PostStatusMessage(new
{
currentDirectory = dirCodec.DirectoryRoot
});
}
/// <summary>
/// Handler for codec changes
/// </summary>
void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
SendVtcFullMessageObject();
}
/// <summary>
///
/// </summary>
void SendIsReady()
{
PostStatusMessage(new
{
isReady = Codec.IsReady
});
}
/// <summary>
/// Helper method to build call status for vtc
/// </summary>
/// <returns></returns>
void SendVtcFullMessageObject()
{
if (!Codec.IsReady)
{
return;
}
var info = Codec.CodecInfo;
PostStatusMessage(new
{
isInCall = Codec.IsInCall,
privacyModeIsOn = Codec.PrivacyModeIsOnFeedback.BoolValue,
sharingContentIsOn = Codec.SharingContentIsOnFeedback.BoolValue,
sharingSource = Codec.SharingSourceFeedback.StringValue,
standbyIsOn = Codec.StandbyIsOnFeedback.StringValue,
calls = Codec.ActiveCalls,
info = new
{
autoAnswerEnabled = info.AutoAnswerEnabled,
e164Alias = info.E164Alias,
h323Id = info.H323Id,
ipAddress = info.IpAddress,
sipPhoneNumber = info.SipPhoneNumber,
sipURI = info.SipUri
},
showSelfViewByDefault = Codec.ShowSelfViewByDefault,
hasDirectory = Codec is IHasDirectory,
hasRecents = Codec is IHasCallHistory,
hasCameras = Codec is IHasCameraControl
});
}
}
}

View File

@@ -3,12 +3,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro.EthernetCommunication;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
@@ -25,6 +27,14 @@ namespace PepperDash.Essentials.Room.Cotija
/// </summary>
public const uint RoomIsOn = 301;
/// <summary>
/// 41
/// </summary>
public const uint PromptForCode = 41;
/// <summary>
/// 42
/// </summary>
public const uint ClientJoined = 42;
/// <summary>
/// 51
/// </summary>
@@ -59,14 +69,15 @@ namespace PepperDash.Essentials.Room.Cotija
/// 63
/// </summary>
public const uint ShutdownStart = 63;
/// <summary>
/// 72
/// </summary>
public const uint SourceHasChanged = 72;
/// <summary>
/// 261 - The start of the range of speed dial visibles
/// </summary>
public const uint SpeedDialVisibleStartJoin = 261;
/// <summary>
/// 501
/// </summary>
public const uint ConfigIsReady = 501;
@@ -91,6 +102,16 @@ namespace PepperDash.Essentials.Room.Cotija
/// 71
/// </summary>
public const uint SelectedSourceKey = 71;
/// <summary>
/// 241
/// </summary>
public const uint SpeedDialNameStartJoin = 241;
/// <summary>
/// 251
/// </summary>
public const uint SpeedDialNumberStartJoin = 251;
/// <summary>
/// 501
@@ -144,6 +165,8 @@ namespace PepperDash.Essentials.Room.Cotija
CotijaDdvc01DeviceBridge SourceBridge;
Ddvc01AtcMessenger AtcMessenger;
/// <summary>
///
@@ -181,6 +204,10 @@ namespace PepperDash.Essentials.Room.Cotija
SetupFunctions();
SetupFeedbacks();
var key = this.Key + "-" + Parent.Key;
AtcMessenger = new Ddvc01AtcMessenger(key, EISC, "/device/audioCodec");
AtcMessenger.RegisterWithAppServer(Parent);
EISC.SigChange += EISC_SigChange;
EISC.OnlineStatusChange += (o, a) =>
{
@@ -215,8 +242,6 @@ namespace PepperDash.Essentials.Room.Cotija
}
}, "mobilebridgedump", "Dumps DDVC01 bridge EISC data b,u,s", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => LoadConfigValues(), "loadddvc", "", ConsoleAccessLevelEnum.AccessOperator);
return base.CustomActivate();
}
@@ -226,6 +251,9 @@ namespace PepperDash.Essentials.Room.Cotija
/// </summary>
void SetupFunctions()
{
#warning need join numbers for these
Parent.AddAction(@"/room/room1/promptForCode", new Action(() => EISC.PulseBool(BoolJoin.PromptForCode)));
Parent.AddAction(@"/room/room1/clientJoined", new Action(() => EISC.PulseBool(BoolJoin.ClientJoined)));
Parent.AddAction(@"/room/room1/status", new Action(SendFullStatus));
@@ -235,13 +263,16 @@ namespace PepperDash.Essentials.Room.Cotija
EISC.PulseBool(BoolJoin.SourceHasChanged);
}));
#warning CHANGE to activityshare. Perhaps
Parent.AddAction(@"/room/room1/defaultsource", new Action(() =>
EISC.PulseBool(BoolJoin.ActivitySharePress)));
Parent.AddAction(@"/room/room1/activityVideo", new Action(() =>
EISC.PulseBool(BoolJoin.ActivityVideoCallPress)));
Parent.AddAction(@"/room/room1/activityPhone", new Action(() =>
EISC.PulseBool(BoolJoin.ActivityPhoneCallPress)));
Parent.AddAction(@"/room/room1/masterVolumeLevel", new Action<ushort>(u =>
Parent.AddAction(@"/room/room1/volumes/master/level", new Action<ushort>(u =>
EISC.SetUshort(UshortJoin.MasterVolumeLevel, u)));
Parent.AddAction(@"/room/room1/masterVolumeMuteToggle", new Action(() =>
Parent.AddAction(@"/room/room1/volumes/master/muteToggle", new Action(() =>
EISC.PulseBool(BoolJoin.MasterVolumeIsMuted)));
Parent.AddAction(@"/room/room1/shutdownStart", new Action(() =>
@@ -252,6 +283,24 @@ namespace PepperDash.Essentials.Room.Cotija
EISC.PulseBool(BoolJoin.ShutdownCancel)));
}
/// <summary>
///
/// </summary>
/// <param name="devKey"></param>
void SetupSourceFunctions(string devKey)
{
SourceDeviceMapDictionary sourceJoinMap = new SourceDeviceMapDictionary();
var prefix = string.Format("/device/{0}/", devKey);
foreach (var item in sourceJoinMap)
{
var join = item.Value;
Parent.AddAction(string.Format("{0}{1}", prefix, item.Key), new PressAndHoldAction(b => EISC.SetBool(join, b)));
}
}
/// <summary>
/// Links feedbacks to whatever is gonna happen!
/// </summary>
@@ -273,16 +322,29 @@ namespace PepperDash.Essentials.Room.Cotija
// Volume things
EISC.SetUShortSigAction(UshortJoin.MasterVolumeLevel, u =>
PostStatusMessage(new
{
masterVolumeLevel = u
}));
PostStatusMessage(new
{
volumes = new
{
master = new
{
level = u
}
}
}));
EISC.SetBoolSigAction(BoolJoin.MasterVolumeIsMuted, b =>
PostStatusMessage(new
{
masterVolumeMuteState = b
}));
PostStatusMessage(new
{
volumes = new
{
master = new
{
muted = b
}
}
}));
// shutdown things
EISC.SetSigTrueAction(BoolJoin.ShutdownCancel, new Action(() =>
@@ -316,15 +378,25 @@ namespace PepperDash.Essentials.Room.Cotija
var co = ConfigReader.ConfigObject;
co.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name;
var version = Assembly.GetExecutingAssembly().GetName().Version;
co.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
//Room
if (co.Rooms == null)
co.Rooms = new List<EssentialsRoomConfig>();
var rm = new EssentialsRoomConfig();
if (co.Rooms.Count == 0)
{
Debug.Console(0, this, "Adding room to config");
co.Rooms.Add(rm);
}
//if (co.Rooms == null)
// always start fresh in case simpl changed
co.Rooms = new List<DeviceConfig>();
var rm = new DeviceConfig();
if (co.Rooms.Count == 0)
{
Debug.Console(0, this, "Adding room to config");
co.Rooms.Add(rm);
}
else
{
Debug.Console(0, this, "Replacing Room[0] in config");
co.Rooms[0] = rm;
}
rm.Name = EISC.StringOutput[501].StringValue;
rm.Key = "room1";
rm.Type = "ddvc01";
@@ -353,22 +425,30 @@ namespace PepperDash.Essentials.Room.Cotija
var name = EISC.StringOutput[i + 1].StringValue;
rmProps.SpeedDials.Add(new DDVC01SpeedDial { Number = num, Name = name});
}
// This MAY need a check
rmProps.AudioCodecKey = "audioCodec";
rmProps.VideoCodecKey = null; // "videoCodec";
// volume control names
var volCount = EISC.UShortOutput[701].UShortValue;
// use Volumes object or?
rmProps.VolumeSliderNames = new List<string>();
for(uint i = 701; i <= 700 + volCount; i++)
{
rmProps.VolumeSliderNames.Add(EISC.StringInput[i].StringValue);
}
//// use Volumes object or?
//rmProps.VolumeSliderNames = new List<string>();
//for(uint i = 701; i <= 700 + volCount; i++)
//{
// rmProps.VolumeSliderNames.Add(EISC.StringInput[i].StringValue);
//}
// There should be cotija devices in here, I think...
if(co.Devices == null)
co.Devices = new List<DeviceConfig>();
// clear out previous DDVC devices
co.Devices.RemoveAll(d => d.Key.StartsWith("source-", StringComparison.OrdinalIgnoreCase));
co.Devices.RemoveAll(d =>
d.Key.StartsWith("source-", StringComparison.OrdinalIgnoreCase)
|| d.Key.Equals("audioCodec", StringComparison.OrdinalIgnoreCase)
|| d.Key.Equals("videoCodec", StringComparison.OrdinalIgnoreCase));
rmProps.SourceListKey = "default";
rm.Properties = JToken.FromObject(rmProps);
@@ -387,6 +467,7 @@ namespace PepperDash.Essentials.Room.Cotija
break;
var icon = EISC.StringOutput[651 + i].StringValue;
var key = EISC.StringOutput[671 + i].StringValue;
var type = EISC.StringOutput[701 + i].StringValue;
Debug.Console(0, this, "Adding source {0} '{1}'", key, name);
@@ -395,9 +476,10 @@ namespace PepperDash.Essentials.Room.Cotija
Name = name,
Order = (int)i + 1,
SourceKey = key,
Type = eSourceListItemType.Route
};
newSl.Add(key, newSLI);
string group = "genericsource";
if (groupMap.ContainsKey(type))
{
@@ -412,10 +494,50 @@ namespace PepperDash.Essentials.Room.Cotija
Type = type
};
co.Devices.Add(devConf);
if (group.ToLower().StartsWith("settopbox")) // Add others here as needed
{
SetupSourceFunctions(key);
}
}
co.SourceLists.Add("default", newSl);
// build "audioCodec" config if we need
if (!string.IsNullOrEmpty(rmProps.AudioCodecKey))
{
var acFavs = new List<PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem>();
for (uint i = 0; i < 4; i++)
{
if (!EISC.GetBool(BoolJoin.SpeedDialVisibleStartJoin + i))
{
break;
}
acFavs.Add(new PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem()
{
Name = EISC.GetString(StringJoin.SpeedDialNameStartJoin + i),
Number = EISC.GetString(StringJoin.SpeedDialNumberStartJoin + i),
Type = PepperDash.Essentials.Devices.Common.Codec.eCodecCallType.Audio
});
}
var acProps = new
{
favorites = acFavs
};
var acStr = "audioCodec";
var acConf = new DeviceConfig()
{
Group = acStr,
Key = acStr,
Name = acStr,
Type = acStr,
Properties = JToken.FromObject(acProps)
};
co.Devices.Add(acConf);
}
Debug.Console(0, this, "******* CONFIG FROM DDVC: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented));
var handler = ConfigurationIsReady;
@@ -427,17 +549,50 @@ namespace PepperDash.Essentials.Room.Cotija
ConfigIsLoaded = true;
}
/// <summary>
///
/// </summary>
void SendFullStatus()
{
if (ConfigIsLoaded)
{
PostStatusMessage(new
{
isOn = EISC.BooleanOutput[BoolJoin.RoomIsOn].BoolValue,
selectedSourceKey = EISC.StringOutput[StringJoin.SelectedSourceKey].StringValue,
masterVolumeLevel = EISC.UShortOutput[UshortJoin.MasterVolumeLevel].UShortValue,
masterVolumeMuteState = EISC.BooleanOutput[BoolJoin.MasterVolumeIsMuted].BoolValue
});
var count = EISC.UShortOutput[801].UShortValue;
Debug.Console(1, this, "The Fader Count is : {0}", count);
// build volumes object, serialize and put in content of method below
var auxFaders = new List<Volume>();
// Create auxFaders
for (uint i = 2; i <= count; i++)
{
auxFaders.Add(
new Volume(string.Format("level-{0}", i),
EISC.UShortOutput[i].UShortValue,
EISC.BooleanOutput[i].BoolValue,
EISC.StringOutput[800 + i].StringValue,
true,
"someting.png"));
}
var volumes = new Volumes();
volumes.Master = new Volume("master",
EISC.UShortOutput[UshortJoin.MasterVolumeLevel].UShortValue,
EISC.BooleanOutput[BoolJoin.MasterVolumeIsMuted].BoolValue,
EISC.StringOutput[801].StringValue,
true,
"something.png");
volumes.AuxFaders = auxFaders;
PostStatusMessage(new
{
isOn = EISC.BooleanOutput[BoolJoin.RoomIsOn].BoolValue,
selectedSourceKey = EISC.StringOutput[StringJoin.SelectedSourceKey].StringValue,
volumes = volumes
});
}
else
{
@@ -448,8 +603,6 @@ namespace PepperDash.Essentials.Room.Cotija
}
}
/// <summary>
/// Helper for posting status message
/// </summary>
@@ -522,86 +675,5 @@ namespace PepperDash.Essentials.Room.Cotija
EISC.StringInput[StringJoin.UserCodeToSystem].StringValue = UserCode;
EISC.StringInput[StringJoin.ServerUrl].StringValue = Parent.Config.ClientAppUrl;
}
/// <summary>
///
/// </summary>
/// <param name="oldKey"></param>
/// <param name="newKey"></param>
void SourceChange(string oldKey, string newKey)
{
/* Example message
* {
"type":"/room/status",
"content": {
"selectedSourceKey": "off",
}
}
*/
//if (type == ChangeType.WillChange)
//{
// // Disconnect from previous source
// if (info != null)
// {
// var previousDev = info.SourceDevice;
// // device type interfaces
// if (previousDev is ISetTopBoxControls)
// (previousDev as ISetTopBoxControls).UnlinkActions(Parent);
// // common interfaces
// if (previousDev is IChannel)
// (previousDev as IChannel).UnlinkActions(Parent);
// if (previousDev is IColor)
// (previousDev as IColor).UnlinkActions(Parent);
// if (previousDev is IDPad)
// (previousDev as IDPad).UnlinkActions(Parent);
// if (previousDev is IDvr)
// (previousDev as IDvr).UnlinkActions(Parent);
// if (previousDev is INumericKeypad)
// (previousDev as INumericKeypad).UnlinkActions(Parent);
// if (previousDev is IPower)
// (previousDev as IPower).UnlinkActions(Parent);
// if (previousDev is ITransport)
// (previousDev as ITransport).UnlinkActions(Parent);
// }
// var huddleRoom = room as EssentialsHuddleSpaceRoom;
// JObject roomStatus = new JObject();
// roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey);
// JObject message = new JObject();
// message.Add("type", "/room/status/");
// message.Add("content", roomStatus);
// Parent.PostToServer(message);
//}
//else
//{
// if (info != null)
// {
// var dev = info.SourceDevice;
// if (dev is ISetTopBoxControls)
// (dev as ISetTopBoxControls).LinkActions(Parent);
// if (dev is IChannel)
// (dev as IChannel).LinkActions(Parent);
// if (dev is IColor)
// (dev as IColor).LinkActions(Parent);
// if (dev is IDPad)
// (dev as IDPad).LinkActions(Parent);
// if (dev is IDvr)
// (dev as IDvr).LinkActions(Parent);
// if (dev is INumericKeypad)
// (dev as INumericKeypad).LinkActions(Parent);
// if (dev is IPower)
// (dev as IPower).LinkActions(Parent);
// if (dev is ITransport)
// (dev as ITransport).LinkActions(Parent);
// }
//}
}
}
}

View File

@@ -0,0 +1,489 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Cotija;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
namespace PepperDash.Essentials
{
public class CotijaEssentialsHuddleSpaceRoomBridge : CotijaBridgeBase
{
public EssentialsRoomBase Room { get; private set; }
public VideoCodecBaseMessenger VCMessenger { get; private set; }
public AudioCodecBaseMessenger ACMessenger { get; private set; }
/// <summary>
///
/// </summary>
public override string RoomName
{
get
{
return Room.Name;
}
}
/// <summary>
///
/// </summary>
/// <param name="parent"></param>
/// <param name="room"></param>
public CotijaEssentialsHuddleSpaceRoomBridge(EssentialsRoomBase room):
base("mobileControlBridge-essentialsHuddle", "Essentials Mobile Control Bridge-Huddle")
{
Room = room;
}
/// <summary>
/// Override of base: calls base to add parent and then registers actions and events.
/// </summary>
/// <param name="parent"></param>
public override void AddParent(CotijaSystemController parent)
{
base.AddParent(parent);
// we add actions to the messaging system with a path, and a related action. Custom action
// content objects can be handled in the controller's LineReceived method - and perhaps other
// sub-controller parsing could be attached to these classes, so that the systemController
// doesn't need to know about everything.
// Source Changes and room off
Parent.AddAction(string.Format(@"/room/{0}/status", Room.Key), new Action(() => SendFullStatus(Room)));
var routeRoom = Room as IRunRouteAction;
if(routeRoom != null)
Parent.AddAction(string.Format(@"/room/{0}/source", Room.Key), new Action<SourceSelectMessageContent>(c =>
routeRoom.RunRouteAction(c.SourceListItem)));
var defaultRoom = Room as IRunDefaultPresentRoute;
if(defaultRoom != null)
Parent.AddAction(string.Format(@"/room/{0}/defaultsource", Room.Key), new Action(() => defaultRoom.RunDefaultPresentRoute()));
var volumeRoom = Room as IHasCurrentVolumeControls;
if (volumeRoom != null)
{
Parent.AddAction(string.Format(@"/room/{0}/volumes/master/level", Room.Key), new Action<ushort>(u =>
(volumeRoom.CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(u)));
Parent.AddAction(string.Format(@"/room/{0}/volumes/master/muteToggle", Room.Key), new Action(() =>
volumeRoom.CurrentVolumeControls.MuteToggle()));
volumeRoom.CurrentVolumeDeviceChange += new EventHandler<VolumeDeviceChangeEventArgs>(Room_CurrentVolumeDeviceChange);
// Registers for initial volume events, if possible
var currentVolumeDevice = volumeRoom.CurrentVolumeControls as IBasicVolumeWithFeedback;
if (currentVolumeDevice != null)
{
currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange;
currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange;
}
}
var sscRoom = Room as IHasCurrentSourceInfoChange;
if(sscRoom != null)
sscRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange);
var vcRoom = Room as IHasVideoCodec;
if (vcRoom != null && vcRoom.VideoCodec != null)
{
var codec = vcRoom.VideoCodec;
var key = vcRoom.VideoCodec.Key + "-" + parent.Key;
VCMessenger = new VideoCodecBaseMessenger(key, vcRoom.VideoCodec, "/device/videoCodec");
VCMessenger.RegisterWithAppServer(Parent);
vcRoom.IsSharingFeedback.OutputChange += new EventHandler<FeedbackEventArgs>(IsSharingFeedback_OutputChange);
}
var acRoom = Room as IHasAudioCodec;
if (acRoom != null && acRoom.AudioCodec != null)
{
var codec = acRoom.AudioCodec;
var key = acRoom.AudioCodec.Key + "-" + parent.Key;
ACMessenger = new AudioCodecBaseMessenger(key, acRoom.AudioCodec, "/device/audioCodec");
ACMessenger.RegisterWithAppServer(Parent);
}
var defCallRm = Room as IRunDefaultCallRoute;
if (defCallRm != null)
{
Parent.AddAction(string.Format(@"/room/{0}/activityVideo", Room.Key), new Action(()=>defCallRm.RunDefaultCallRoute()));
}
Parent.AddAction(string.Format(@"/room/{0}/shutdownStart", Room.Key), new Action(() => Room.StartShutdown(eShutdownType.Manual)));
Parent.AddAction(string.Format(@"/room/{0}/shutdownEnd", Room.Key), new Action(() => Room.ShutdownPromptTimer.Finish()));
Parent.AddAction(string.Format(@"/room/{0}/shutdownCancel", Room.Key), new Action(() => Room.ShutdownPromptTimer.Cancel()));
Room.OnFeedback.OutputChange += OnFeedback_OutputChange;
Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
Room.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted;
Room.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished;
Room.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
// sharing source
string shareText;
bool isSharing;
#warning This share update needs to happen on source change as well!
var vcRoom = Room as IHasVideoCodec;
var srcInfoRoom = Room as IHasCurrentSourceInfoChange;
if (vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null)
{
shareText = srcInfoRoom.CurrentSourceInfo.PreferredName;
isSharing = true;
}
else
{
shareText = "None";
isSharing = false;
}
PostStatusMessage(new
{
share = new
{
currentShareText = shareText,
isSharing = isSharing
}
});
}
///// <summary>
///// Handler for codec changes
///// </summary>
//void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
//{
// PostStatusMessage(new
// {
// calls = GetCallsMessageObject(),
// //vtc = GetVtcCallsMessageObject()
// });
//}
/// <summary>
/// Helper for posting status message
/// </summary>
/// <param name="contentObject">The contents of the content object</param>
void PostStatusMessage(object contentObject)
{
Parent.SendMessageToServer(JObject.FromObject(new
{
type = "/room/status/",
content = contentObject
}));
}
/// <summary>
/// Handler for cancelled shutdown
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("state", "wasCancelled");
JObject message = new JObject();
message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
/// <summary>
/// Handler for when shutdown finishes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("state", "hasFinished");
JObject message = new JObject();
message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
/// <summary>
/// Handler for when shutdown starts
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ShutdownPromptTimer_HasStarted(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("state", "hasStarted");
roomStatus.Add("duration", Room.ShutdownPromptTimer.SecondsToCount);
JObject message = new JObject();
message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
// equivalent JS message:
// Post( { type: '/room/status/', content: { shutdown: 'hasStarted', duration: Room.ShutdownPromptTimer.SecondsToCount })
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(new
{
isWarmingUp = e.BoolValue
});
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(new
{
isCoolingDown = e.BoolValue
});
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void OnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(new
{
isOn = e.BoolValue
});
}
void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e)
{
if (e.OldDev is IBasicVolumeWithFeedback)
{
var oldDev = e.OldDev as IBasicVolumeWithFeedback;
oldDev.MuteFeedback.OutputChange -= MuteFeedback_OutputChange;
oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange;
}
if (e.NewDev is IBasicVolumeWithFeedback)
{
var newDev = e.NewDev as IBasicVolumeWithFeedback;
newDev.MuteFeedback.OutputChange += MuteFeedback_OutputChange;
newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange;
}
}
/// <summary>
/// Event handler for mute changes
/// </summary>
void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(new
{
volumes = new
{
master = new
{
muted = e.BoolValue
}
}
});
}
/// <summary>
/// Handles Volume changes on room
/// </summary>
void VolumeLevelFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(new
{
volumes = new
{
master = new
{
level = e.IntValue
}
}
});
}
void Room_CurrentSingleSourceChange(EssentialsRoomBase room, PepperDash.Essentials.Core.SourceListItem info, ChangeType type)
{
/* Example message
* {
"type":"/room/status",
"content": {
"selectedSourceKey": "off",
}
}
*/
if (type == ChangeType.WillChange)
{
// Disconnect from previous source
if (info != null)
{
var previousDev = info.SourceDevice;
// device type interfaces
if (previousDev is ISetTopBoxControls)
(previousDev as ISetTopBoxControls).UnlinkActions(Parent);
// common interfaces
if (previousDev is IChannel)
(previousDev as IChannel).UnlinkActions(Parent);
if (previousDev is IColor)
(previousDev as IColor).UnlinkActions(Parent);
if (previousDev is IDPad)
(previousDev as IDPad).UnlinkActions(Parent);
if (previousDev is IDvr)
(previousDev as IDvr).UnlinkActions(Parent);
if (previousDev is INumericKeypad)
(previousDev as INumericKeypad).UnlinkActions(Parent);
if (previousDev is IPower)
(previousDev as IPower).UnlinkActions(Parent);
if (previousDev is ITransport)
(previousDev as ITransport).UnlinkActions(Parent);
}
}
else // did change
{
if (info != null)
{
var dev = info.SourceDevice;
if (dev is ISetTopBoxControls)
(dev as ISetTopBoxControls).LinkActions(Parent);
if (dev is IChannel)
(dev as IChannel).LinkActions(Parent);
if (dev is IColor)
(dev as IColor).LinkActions(Parent);
if (dev is IDPad)
(dev as IDPad).LinkActions(Parent);
if (dev is IDvr)
(dev as IDvr).LinkActions(Parent);
if (dev is INumericKeypad)
(dev as INumericKeypad).LinkActions(Parent);
if (dev is IPower)
(dev as IPower).LinkActions(Parent);
if (dev is ITransport)
(dev as ITransport).LinkActions(Parent);
var srcRm = room as IHasCurrentSourceInfoChange;
PostStatusMessage(new
{
selectedSourceKey = srcRm.CurrentSourceInfoKey
});
}
}
}
/// <summary>
/// Posts the full status of the room to the server
/// </summary>
/// <param name="room"></param>
void SendFullStatus(EssentialsRoomBase room)
{
var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null;
var rmVc = room as IHasCurrentVolumeControls;
var volumes = new Volumes();
if (rmVc != null)
{
var vc = rmVc.CurrentVolumeControls as IBasicVolumeWithFeedback;
if (rmVc != null)
{
volumes.Master = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, "");
}
}
PostStatusMessage(new
{
//calls = GetCallsMessageObject(),
isOn = room.OnFeedback.BoolValue,
selectedSourceKey = sourceKey,
//vtc = GetVtcCallsMessageObject(),
volumes = volumes
});
}
///// <summary>
///// Helper to return a anonymous object with the call data for JSON message
///// </summary>
///// <returns></returns>
//object GetCallsMessageObject()
//{
// var callRm = Room as IHasVideoCodec;
// if (callRm == null)
// return null;
// return new
// {
// activeCalls = callRm.VideoCodec.ActiveCalls,
// callType = callRm.CallTypeFeedback.IntValue,
// inCall = callRm.InCallFeedback.BoolValue,
// isSharing = callRm.IsSharingFeedback.BoolValue,
// privacyModeIsOn = callRm.PrivacyModeIsOnFeedback.BoolValue
// };
//}
///// <summary>
///// Helper method to build call status for vtc
///// </summary>
///// <returns></returns>
//object GetVtcCallsMessageObject()
//{
// var callRm = Room as IHasVideoCodec;
// object vtc = null;
// if (callRm != null)
// {
// var codec = callRm.VideoCodec;
// vtc = new
// {
// isInCall = codec.IsInCall,
// calls = codec.ActiveCalls
// };
// }
// return vtc;
//}
}
/// <summary>
///
/// </summary>
public class SourceSelectMessageContent
{
public string SourceListItem { get; set; }
}
/// <summary>
///
/// </summary>
/// <param name="b"></param>
public delegate void PressAndHoldAction(bool b);
}

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Room.Cotija
{
/// <summary>
/// Contains all of the default joins that map to API funtions
/// </summary>
public class SourceDeviceMapDictionary : Dictionary<string, uint>
{
public SourceDeviceMapDictionary(): base()
{
var dictionary = new Dictionary<string, uint>
{
{"preset01", 101},
{"preset02", 102},
{"preset03", 103},
{"preset04", 104},
{"preset05", 105},
{"preset06", 106},
{"preset07", 107},
{"preset08", 108},
{"preset09", 109},
{"preset10", 110},
{"preset11", 111},
{"preset12", 112},
{"preset13", 113},
{"preset14", 114},
{"preset15", 115},
{"preset16", 116},
{"preset17", 117},
{"preset18", 118},
{"preset19", 119},
{"preset20", 120},
{"preset21", 121},
{"preset22", 122},
{"preset23", 123},
{"preset24", 124},
{"num0", 130},
{"num1", 131},
{"num2", 132},
{"num3", 133},
{"num4", 134},
{"num5", 135},
{"num6", 136},
{"num7", 137},
{"num8", 138},
{"num9", 139},
{"numDash", 140},
{"numEnter", 141},
{"chanUp", 142},
{"chanDown", 143},
{"lastChan", 144},
{"exit", 145},
{"powerToggle", 146},
{"red", 147},
{"green", 148},
{"yellow", 149},
{"blue", 150},
{"video", 151},
{"previous", 152},
{"next", 153},
{"rewind", 154},
{"ffwd", 155},
{"closedCaption", 156},
{"stop", 157},
{"pause", 158},
{"up", 159},
{"down", 160},
{"left", 161},
{"right", 162},
{"settings", 163},
{"info", 164},
{"return", 165},
{"guide", 166},
{"reboot", 167},
{"dvrList", 168},
{"replay", 169},
{"play", 170},
{"select", 171},
{"record", 172},
{"menu", 173},
{"topMenu", 174},
{"prevTrack", 175},
{"nextTrack", 176},
{"powerOn", 177},
{"powerOff", 178},
{"dot", 179}
};
foreach (var item in dictionary)
{
this.Add(item.Key, item.Value);
}
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Room.Cotija
{
public class Volumes
{
[JsonProperty("master")]
public Volume Master { get; set; }
[JsonProperty("auxFaders")]
public List<Volume> AuxFaders { get; set; }
public Volumes()
{
AuxFaders = new List<Volume>();
}
}
public class Volume
{
[JsonProperty("key")]
public string Key { get; set; }
[JsonProperty("level")]
public ushort Level { get; set; }
[JsonProperty("muted")]
public bool Muted { get; set; }
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("hasMute")]
public bool HasMute { get; set; }
[JsonProperty("muteIcon")]
public string MuteIcon { get; set; }
public Volume(string key, ushort level, bool muted, string label, bool hasMute, string muteIcon)
{
Key = key;
Level = level;
Muted = muted;
Label = label;
HasMute = hasMute;
MuteIcon = muteIcon;
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.EthernetCommunication;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Lighting;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.CrestronIO;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.DSP;
namespace PepperDash.Essentials.Bridges
{
/// <summary>
/// Base class for all bridge class variants
/// </summary>
public class BridgeBase : Device
{
public BridgeApi Api { get; private set; }
public BridgeBase(string key) :
base(key)
{
}
}
/// <summary>
/// Base class for bridge API variants
/// </summary>
public abstract class BridgeApi : Device
{
public BridgeApi(string key) :
base(key)
{
}
}
/// <summary>
/// Bridge API using EISC
/// </summary>
public class EiscApi : BridgeApi
{
public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc { get; private set; }
public EiscApi(DeviceConfig dc) :
base(dc.Key)
{
PropertiesConfig = JsonConvert.DeserializeObject<EiscApiPropertiesConfig>(dc.Properties.ToString());
Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(PropertiesConfig.Control.IpIdInt, PropertiesConfig.Control.TcpSshProperties.Address, Global.ControlSystem);
Eisc.SigChange += new Crestron.SimplSharpPro.DeviceSupport.SigEventHandler(Eisc_SigChange);
Eisc.Register();
AddPostActivationAction( () =>
{
Debug.Console(1, this, "Linking Devices...");
foreach (var d in PropertiesConfig.Devices)
{
var device = DeviceManager.GetDeviceForKey(d.DeviceKey);
if (device != null)
{
if (device is PepperDash.Essentials.Core.Monitoring.SystemMonitorController)
{
(device as PepperDash.Essentials.Core.Monitoring.SystemMonitorController).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is GenericComm)
{
(device as GenericComm).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is CameraBase)
{
(device as CameraBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is PepperDash.Essentials.Core.TwoWayDisplayBase)
{
(device as TwoWayDisplayBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is DmChassisController)
{
(device as DmChassisController).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is DmTxControllerBase)
{
(device as DmTxControllerBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is DmRmcControllerBase)
{
(device as DmRmcControllerBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is GenericRelayDevice)
{
(device as GenericRelayDevice).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is IDigitalInput)
{
(device as IDigitalInput).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is LightingBase)
{
(device as LightingBase).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is DigitalLogger)
{
(device as DigitalLogger).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is TVOneCorio)
{
(device as TVOneCorio).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
else if (device is QscDsp)
{
(device as QscDsp).LinkToApi(Eisc, d.JoinStart, d.JoinMapKey);
continue;
}
}
}
Debug.Console(1, this, "Devices Linked.");
});
}
/// <summary>
/// Handles incoming sig changes
/// </summary>
/// <param name="currentDevice"></param>
/// <param name="args"></param>
void Eisc_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args)
{
if (Debug.Level >= 1)
Debug.Console(1, this, "EiscApi change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
var uo = args.Sig.UserObject;
if (uo is Action<bool>)
(uo as Action<bool>)(args.Sig.BoolValue);
else if (uo is Action<ushort>)
(uo as Action<ushort>)(args.Sig.UShortValue);
else if (uo is Action<string>)
(uo as Action<string>)(args.Sig.StringValue);
}
}
public class EiscApiPropertiesConfig
{
[JsonProperty("control")]
public EssentialsControlPropertiesConfig Control { get; set; }
[JsonProperty("devices")]
public List<ApiDevice> Devices { get; set; }
public class ApiDevice
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("joinStart")]
public uint JoinStart { get; set; }
[JsonProperty("joinMapKey")]
public string JoinMapKey { get; set; }
}
}
}

View File

@@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Bridges;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.EthernetCommunication;
namespace PepperDash.Essentials
{
public class BridgeFactory
{
public static IKeyed GetDevice(DeviceConfig dc)
{
// ? why is this static JTA 2018-06-13?
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var propAnon = new { };
var typeName = dc.Type.ToLower();
var groupName = dc.Group.ToLower();
//Debug.Console(2, "Name {0}, Key {1}, Type {2}, Properties {3}", name, key, type, properties.ToString());
if (typeName == "eiscapi")
{
return new EiscApi(dc);
}
return null;
}
}
public class CommBridge : Device
{
public CommBridgeProperties Properties { get; private set; }
public List<IBasicCommunication> CommDevices { get; private set; }
public CommBridge(string key, string name, JToken properties)
: base(key, name)
{
Properties = JsonConvert.DeserializeObject<CommBridgeProperties>(properties.ToString());
}
public override bool CustomActivate()
{
// Create EiscApis
if (Properties.Eiscs != null)
{
foreach (var eisc in Properties.Eiscs)
{
var ApiEisc = new BridgeApiEisc(eisc.IpId, eisc.Hostname);
}
}
foreach (var deviceKey in Properties.CommDevices)
{
var device = DeviceManager.GetDeviceForKey(deviceKey);
if (device != null)
{
Debug.Console(0, "deviceKey {0} Found in Device Manager", device.Key);
CommDevices.Add(device as IBasicCommunication);
}
else
{
Debug.Console(0, "deviceKey {0} Not Found in Device Manager", deviceKey);
}
}
// Iterate through all the CommDevices and link up their Actions and Feedbacks
Debug.Console(0, "Bridge {0} Activated", this.Name);
return true;
}
}
public class EiscBridgeProperties
{
public string ParentDeviceKey { get; set; }
public eApiType ApiType { get; set; }
public List<EiscProperties> Eiscs { get; set; }
public string ApiOverrideFilePath { get; set; }
public class EiscProperties
{
public string IpId { get; set; }
public string Hostname { get; set; }
}
}
public class CommBridgeProperties : EiscBridgeProperties
{
public List<string> CommDevices { get; set; }
}
public enum eApiType { Eisc = 0 }
public class BridgeApiEisc
{
public uint Ipid { get; private set; }
public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc { get; private set; }
public BridgeApiEisc(string ipid, string hostname)
{
Ipid = (UInt32)int.Parse(ipid, System.Globalization.NumberStyles.HexNumber);
Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(Ipid, hostname, Global.ControlSystem);
Eisc.Register();
Eisc.SigChange += Eisc_SigChange;
Debug.Console(0, "BridgeApiEisc Created at Ipid {0}", ipid);
}
void Eisc_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args)
{
if (Debug.Level >= 1)
Debug.Console(1, "BridgeApiEisc change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
var uo = args.Sig.UserObject;
if (uo is Action<bool>)
(uo as Action<bool>)(args.Sig.BoolValue);
else if (uo is Action<ushort>)
(uo as Action<ushort>)(args.Sig.UShortValue);
else if (uo is Action<string>)
(uo as Action<string>)(args.Sig.StringValue);
}
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
using PepperDash.Essentials.Core.Routing;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.EthernetCommunication;
using PepperDash.Essentials.Bridges;
namespace PepperDash.Essentials {
public class BridgeFactory {
public static IKeyed GetDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) {
// ? why is this static JTA 2018-06-13?
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var propAnon = new { };
JsonConvert.DeserializeAnonymousType(dc.Properties.ToString(), propAnon);
var typeName = dc.Type.ToLower();
var groupName = dc.Group.ToLower();
Debug.Console(2, "Name {0}, Key {1}, Type {2}, Properties {3}", name, key, type, properties.ToString());
if (typeName == "essentialdm")
{
return new EssentialDM(key, name, properties);
}
else if (typeName == "essentialcomm")
{
Debug.Console(2, "Launch Essential Comm");
return new EssentialComm(key, name, properties);
}
else if (typeName == "essentialdsp")
{
Debug.Console(2, "Launch EssentialDsp");
return new EssentialDsp(key, name, properties);
}
else if (typeName == "essentialstvone")
{
Debug.Console(2, "Launch essentialstvone");
return new EssentialsTVOne(key, name, properties);
}
else if (typeName == "essentialslighting")
{
Debug.Console(2, "Launch essentialslighting");
return new EssentialsLightsBridge(key, name, properties);
}
else if (typeName == "eiscapi")
{
return new EiscApi(dc);
}
return null;
}
}
public class BridgeApiEisc {
public uint Ipid;
public ThreeSeriesTcpIpEthernetIntersystemCommunications Eisc;
public BridgeApiEisc(string ipid) {
Ipid = (UInt32)int.Parse(ipid, System.Globalization.NumberStyles.HexNumber);
Eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(Ipid, "127.0.0.2", Global.ControlSystem);
Eisc.Register();
Eisc.SigChange += Eisc_SigChange;
Debug.Console(2, "BridgeApiEisc Created at Ipid {0}", ipid);
}
void Eisc_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args) {
if (Debug.Level >= 1)
Debug.Console(2, "DDVC EISC change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
var uo = args.Sig.UserObject;
if (uo is Action<bool>)
(uo as Action<bool>)(args.Sig.BoolValue);
else if (uo is Action<ushort>)
(uo as Action<ushort>)(args.Sig.UShortValue);
else if (uo is Action<string>)
(uo as Action<string>)(args.Sig.StringValue);
}
}
}

View File

@@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
namespace PepperDash.Essentials.Bridges
{
public static class CameraControllerApiExtensions
{
public static BasicTriList _TriList;
public static CameraControllerJoinMap JoinMap;
public static void LinkToApi(this PepperDash.Essentials.Devices.Common.Cameras.CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey)
{
JoinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as CameraControllerJoinMap;
_TriList = trilist;
if (JoinMap == null)
{
JoinMap = new CameraControllerJoinMap();
}
JoinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, "Linking to Bridge Type {0}", cameraDevice.GetType().Name.ToString());
var commMonitor = cameraDevice as ICommunicationMonitor;
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[JoinMap.IsOnline]);
trilist.SetBoolSigAction(JoinMap.Left, (b) =>
{
if (b)
{
cameraDevice.PanLeft();
}
else
{
cameraDevice.Stop();
}
});
trilist.SetBoolSigAction(JoinMap.Right, (b) =>
{
if (b)
{
cameraDevice.PanRight();
}
else
{
cameraDevice.Stop();
}
});
trilist.SetBoolSigAction(JoinMap.Up, (b) =>
{
if (b)
{
cameraDevice.TiltUp();
}
else
{
cameraDevice.Stop();
}
});
trilist.SetBoolSigAction(JoinMap.Down, (b) =>
{
if (b)
{
cameraDevice.TiltDown();
}
else
{
cameraDevice.Stop();
}
});
trilist.SetBoolSigAction(JoinMap.ZoomIn, (b) =>
{
if (b)
{
cameraDevice.ZoomIn();
}
else
{
cameraDevice.Stop();
}
});
trilist.SetBoolSigAction(JoinMap.ZoomOut, (b) =>
{
if (b)
{
cameraDevice.ZoomOut();
}
else
{
cameraDevice.Stop();
}
});
if (cameraDevice.GetType().Name.ToString().ToLower() == "cameravisca")
{
var viscaCamera = cameraDevice as PepperDash.Essentials.Devices.Common.Cameras.CameraVisca;
trilist.SetSigTrueAction(JoinMap.PowerOn, () => viscaCamera.PowerOn());
trilist.SetSigTrueAction(JoinMap.PowerOff, () => viscaCamera.PowerOff());
viscaCamera.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[JoinMap.PowerOn]);
viscaCamera.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[JoinMap.PowerOff]);
viscaCamera.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[JoinMap.IsOnline]);
for (int i = 0; i < JoinMap.NumberOfPresets; i++)
{
int tempNum = i;
trilist.SetSigTrueAction((ushort)(JoinMap.PresetRecallOffset + tempNum), () =>
{
viscaCamera.RecallPreset(tempNum);
});
trilist.SetSigTrueAction((ushort)(JoinMap.PresetSaveOffset + tempNum), () =>
{
viscaCamera.SavePreset(tempNum);
});
}
}
}
}
public class CameraControllerJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint PowerOff { get; set; }
public uint PowerOn { get; set; }
public uint Up { get; set; }
public uint Down { get; set; }
public uint Left { get; set; }
public uint Right { get; set; }
public uint ZoomIn { get; set; }
public uint ZoomOut { get; set; }
public uint PresetRecallOffset { get; set; }
public uint PresetSaveOffset { get; set; }
public uint NumberOfPresets { get; set; }
public CameraControllerJoinMap()
{
// Digital
IsOnline = 9;
PowerOff = 8;
PowerOn = 7;
Up = 1;
Down = 2;
Left = 3;
Right = 4;
ZoomIn = 5;
ZoomOut = 6;
PresetRecallOffset = 10;
PresetSaveOffset = 30;
NumberOfPresets = 5;
// Analog
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
PowerOff = PowerOff + joinOffset;
PowerOn = PowerOn + joinOffset;
Up = Up + joinOffset;
Down = Down + joinOffset;
Left = Left + joinOffset;
Right = Right + joinOffset;
ZoomIn = ZoomIn + joinOffset;
ZoomOut = ZoomOut + joinOffset;
PresetRecallOffset = PresetRecallOffset + joinOffset;
PresetSaveOffset = PresetSaveOffset + joinOffset;
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
namespace PepperDash.Essentials.Bridges
{
public static class DigitalLoggerApiExtensions
{
public static void LinkToApi(this DigitalLogger DigitalLogger, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as DigitalLoggerJoinMap;
if (joinMap == null)
joinMap = new DigitalLoggerJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, DigitalLogger, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
for (uint i = 1; i <= DigitalLogger.CircuitCount; i++)
{
var circuit = i;
DigitalLogger.CircuitNameFeedbacks[circuit - 1].LinkInputSig(trilist.StringInput[joinMap.CircuitNames + circuit]);
DigitalLogger.CircuitIsCritical[circuit - 1].LinkInputSig(trilist.BooleanInput[joinMap.CircuitIsCritical + circuit]);
DigitalLogger.CircuitState[circuit - 1].LinkInputSig(trilist.BooleanInput[joinMap.CircuitState + circuit]);
trilist.SetSigTrueAction(joinMap.CircuitCycle + circuit, () => DigitalLogger.CycleCircuit(circuit - 1));
trilist.SetSigTrueAction(joinMap.CircuitOnCmd + circuit, () => DigitalLogger.TurnOnCircuit(circuit - 1));
trilist.SetSigTrueAction(joinMap.CircuitOffCmd + circuit, () => DigitalLogger.TurnOffCircuit(circuit - 1));
}
}
}
public class DigitalLoggerJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint CircuitNames { get; set; }
public uint CircuitState { get; set; }
public uint CircuitCycle { get; set; }
public uint CircuitIsCritical { get; set; }
public uint CircuitOnCmd { get; set; }
public uint CircuitOffCmd { get; set; }
public DigitalLoggerJoinMap()
{
// Digital
IsOnline = 9;
CircuitState = 0;
CircuitCycle = 0;
CircuitIsCritical = 10;
CircuitOnCmd = 10;
CircuitOffCmd = 20;
// Serial
CircuitNames = 0;
// Analog
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
CircuitNames = CircuitNames + joinOffset;
CircuitState = CircuitState + joinOffset;
CircuitCycle = CircuitCycle + joinOffset;
CircuitIsCritical = CircuitIsCritical + joinOffset;
CircuitOnCmd = CircuitOnCmd + joinOffset;
CircuitOffCmd = CircuitOffCmd + joinOffset;
}
}
}

View File

@@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
namespace PepperDash.Essentials.Bridges
{
public static class DisplayControllerApiExtensions
{
public static BasicTriList _TriList;
public static DisplayControllerJoinMap JoinMap;
public static int InputNumber;
public static IntFeedback InputNumberFeedback;
public static List<string> InputKeys = new List<string>();
public static void LinkToApi(this PepperDash.Essentials.Core.TwoWayDisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey)
{
JoinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as DisplayControllerJoinMap;
_TriList = trilist;
if (JoinMap == null)
{
JoinMap = new DisplayControllerJoinMap();
}
JoinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, "Linking to Bridge Type {0}", displayDevice.GetType().Name.ToString());
trilist.StringInput[JoinMap.Name].StringValue = displayDevice.GetType().Name.ToString();
InputNumberFeedback = new IntFeedback(() => { return InputNumber;});
InputNumberFeedback.LinkInputSig(trilist.UShortInput[JoinMap.InputSelect]);
var commMonitor = displayDevice as ICommunicationMonitor;
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[JoinMap.IsOnline]);
// Poewer Off
trilist.SetSigTrueAction(JoinMap.PowerOff, () =>
{
InputNumber = 102;
InputNumberFeedback.FireUpdate();
displayDevice.PowerOff();
});
displayDevice.PowerIsOnFeedback.OutputChange += new EventHandler<FeedbackEventArgs>(PowerIsOnFeedback_OutputChange);
displayDevice.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[JoinMap.PowerOff]);
// Poewer On
trilist.SetSigTrueAction(JoinMap.PowerOn, () =>
{
InputNumber = 0;
InputNumberFeedback.FireUpdate();
displayDevice.PowerOn();
});
displayDevice.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[JoinMap.PowerOn]);
int count = 1;
foreach (var input in displayDevice.InputPorts)
{
InputKeys.Add(input.Key.ToString());
var tempKey = InputKeys.ElementAt(count - 1);
trilist.SetSigTrueAction((ushort)(JoinMap.InputSelectOffset + count), () => { displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector); });
trilist.StringInput[(ushort)(JoinMap.InputNamesOffset + count)].StringValue = input.Key.ToString();
count++;
}
displayDevice.CurrentInputFeedback.OutputChange += new EventHandler<FeedbackEventArgs>(CurrentInputFeedback_OutputChange);
trilist.SetUShortSigAction(JoinMap.InputSelect, (a) =>
{
if (a == 0)
{
displayDevice.PowerOff();
InputNumber = 0;
}
else if (a > 0 && a < displayDevice.InputPorts.Count && a != InputNumber)
{
displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(a - 1).Selector);
InputNumber = a;
}
else if (a == 102)
{
displayDevice.PowerToggle();
}
InputNumberFeedback.FireUpdate();
});
}
static void CurrentInputFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
Debug.Console(0, "CurrentInputFeedback_OutputChange {0}", e.StringValue);
}
static void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
// Debug.Console(0, "PowerIsOnFeedback_OutputChange {0}", e.BoolValue);
if (!e.BoolValue)
{
InputNumber = 102;
InputNumberFeedback.FireUpdate();
}
else
{
InputNumber = 0;
InputNumberFeedback.FireUpdate();
}
}
}
public class DisplayControllerJoinMap : JoinMapBase
{
public uint Name { get; set; }
public uint InputNamesOffset { get; set; }
public uint InputSelectOffset { get; set; }
public uint IsOnline { get; set; }
public uint PowerOff { get; set; }
public uint InputSelect { get; set; }
public uint PowerOn { get; set; }
public uint SelectScene { get; set; }
public uint LightingSceneOffset { get; set; }
public uint ButtonVisibilityOffset { get; set; }
public uint IntegrationIdSet { get; set; }
public DisplayControllerJoinMap()
{
// Digital
IsOnline = 50;
PowerOff = 1;
PowerOn = 2;
InputSelect = 4;
IntegrationIdSet = 1;
LightingSceneOffset = 10;
ButtonVisibilityOffset = 40;
Name = 1;
InputNamesOffset = 10;
InputSelectOffset = 4;
// Analog
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
PowerOff = PowerOff + joinOffset;
PowerOn = PowerOn + joinOffset;
SelectScene = SelectScene + joinOffset;
LightingSceneOffset = LightingSceneOffset + joinOffset;
ButtonVisibilityOffset = ButtonVisibilityOffset + joinOffset;
Name = Name + joinOffset;
InputNamesOffset = InputNamesOffset + joinOffset;
InputSelectOffset = InputSelectOffset + joinOffset;
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.DM;
namespace PepperDash.Essentials.Bridges
{
public static class DmChassisControllerApiExtentions
{
public static void LinkToApi(this DmChassisController dmChassis, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as DmChassisControllerJoinMap;
if (joinMap == null)
joinMap = new DmChassisControllerJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, dmChassis, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
dmChassis.IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
// Link up outputs
for (uint i = 1; i <= dmChassis.Chassis.NumberOfOutputs - 1; i++)
{
var ioSlot = i;
// Control
trilist.SetUShortSigAction(joinMap.OutputVideo + ioSlot, new Action<ushort>(o => dmChassis.ExecuteSwitch(o, ioSlot, eRoutingSignalType.Video)));
trilist.SetUShortSigAction(joinMap.OutputAudio + ioSlot, new Action<ushort>(o => dmChassis.ExecuteSwitch(o, ioSlot, eRoutingSignalType.Audio)));
if (dmChassis.TxDictionary.ContainsKey(ioSlot))
{
Debug.Console(2, "Creating Tx Feedbacks {0}", ioSlot);
var TxKey = dmChassis.TxDictionary[ioSlot];
var TxDevice = DeviceManager.GetDeviceForKey(TxKey) as DmTxControllerBase;
TxDevice.IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.InputEndpointOnline + ioSlot]);
// TxDevice.AnyVideoInput.VideoStatus.VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputEndpointOnline + ioSlot]);
// trilist.SetUShortSigAction((ApiMap.HdcpSupport[ioSlot]), u => TxDevice.SetHdcpSupportAll((ePdtHdcpSupport)(u)));
// TxDevice.HdcpSupportAllFeedback.LinkInputSig(trilist.UShortInput[joinMap. + ioSlot]);
// trilist.UShortInput[ApiMap.HdcpSupportCapability[ioSlot]].UShortValue = TxDevice.HdcpSupportCapability;
}
else
{
// dmChassis.VideoInputSyncFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[ApiMap.TxVideoSyncStatus[ioSlot]]);
}
if (dmChassis.RxDictionary.ContainsKey(ioSlot))
{
Debug.Console(2, "Creating Rx Feedbacks {0}", ioSlot);
var RxKey = dmChassis.RxDictionary[ioSlot];
var RxDevice = DeviceManager.GetDeviceForKey(RxKey) as DmRmcControllerBase;
RxDevice.IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.OutputEndpointOnline + ioSlot]);
}
// Feedback
dmChassis.VideoOutputFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[joinMap.OutputVideo + ioSlot]);
dmChassis.AudioOutputFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[joinMap.OutputAudio + ioSlot]);
dmChassis.VideoInputSyncFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[joinMap.VideoSyncStatus + ioSlot]);
dmChassis.OutputNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputNames + ioSlot]);
dmChassis.InputNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.InputNames + ioSlot]);
dmChassis.OutputVideoRouteNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputCurrentVideoInputNames + ioSlot]);
dmChassis.OutputAudioRouteNameFeedbacks[ioSlot].LinkInputSig(trilist.StringInput[joinMap.OutputCurrentAudioInputNames + ioSlot]);
// dmChassis.InputEndpointOnlineFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[joinMap.InputEndpointOnline + ioSlot]);
// dmChassis.OutputEndpointOnlineFeedbacks[ioSlot].LinkInputSig(trilist.BooleanInput[joinMap.OutputEndpointOnline + ioSlot]);
}
}
public class DmChassisControllerJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint OutputVideo { get; set; }
public uint OutputAudio { get; set; }
public uint VideoSyncStatus { get; set; }
public uint InputNames { get; set; }
public uint OutputNames { get; set; }
public uint OutputCurrentVideoInputNames { get; set; }
public uint OutputCurrentAudioInputNames { get; set; }
public uint InputCurrentResolution { get; set; }
public uint InputEndpointOnline { get; set; }
public uint OutputEndpointOnline { get; set; }
//public uint HdcpSupport { get; set; }
//public uint HdcpSupportCapability { get; set; }
public DmChassisControllerJoinMap()
{
IsOnline = 11;
OutputVideo = 100; //101-299
OutputAudio = 300; //301-499
VideoSyncStatus = 100; //101-299
InputNames = 100; //101-299
OutputNames = 300; //301-499
OutputCurrentVideoInputNames = 2000; //2001-2199
OutputCurrentAudioInputNames = 2200; //2201-2399
InputCurrentResolution = 2400; // 2401-2599
InputEndpointOnline = 500;
OutputEndpointOnline = 700;
//HdcpSupport = 1000; //1001-1199
//HdcpSupportCapability = 1200; //1201-1399
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
OutputVideo = OutputVideo + joinOffset;
OutputAudio = OutputAudio + joinOffset;
VideoSyncStatus = VideoSyncStatus + joinOffset;
InputNames = InputNames + joinOffset;
OutputNames = OutputNames + joinOffset;
OutputCurrentVideoInputNames = OutputCurrentVideoInputNames + joinOffset;
OutputCurrentAudioInputNames = OutputCurrentAudioInputNames + joinOffset;
InputCurrentResolution = InputCurrentResolution + joinOffset;
InputEndpointOnline = InputEndpointOnline + joinOffset;
OutputEndpointOnline = OutputEndpointOnline + joinOffset;
//HdcpSupport = HdcpSupport + joinOffset;
//HdcpSupportCapability = HdcpSupportCapability + joinOffset;
}
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.DM;
namespace PepperDash.Essentials.Bridges
{
public static class DmRmcControllerApiExtensions
{
public static void LinkToApi(this DmRmcControllerBase rmc, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as DmRmcControllerJoinMap;
if (joinMap == null)
joinMap = new DmRmcControllerJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, rmc, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
rmc.IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
if(rmc.VideoOutputResolutionFeedback != null)
rmc.VideoOutputResolutionFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentOutputResolution]);
if(rmc.EdidManufacturerFeedback != null)
rmc.EdidManufacturerFeedback.LinkInputSig(trilist.StringInput[joinMap.EdidManufacturer]);
if(rmc.EdidNameFeedback != null)
rmc.EdidNameFeedback.LinkInputSig(trilist.StringInput[joinMap.EdidName]);
if(rmc.EdidPreferredTimingFeedback != null)
rmc.EdidPreferredTimingFeedback.LinkInputSig(trilist.StringInput[joinMap.EdidPrefferedTiming]);
if(rmc.EdidSerialNumberFeedback != null)
rmc.EdidSerialNumberFeedback.LinkInputSig(trilist.StringInput[joinMap.EdidSerialNumber]);
}
public class DmRmcControllerJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint CurrentOutputResolution { get; set; }
public uint EdidManufacturer { get; set; }
public uint EdidName { get; set; }
public uint EdidPrefferedTiming { get; set; }
public uint EdidSerialNumber { get; set; }
public DmRmcControllerJoinMap()
{
// Digital
IsOnline = 1;
// Serial
CurrentOutputResolution = 1;
EdidManufacturer = 2;
EdidName = 3;
EdidPrefferedTiming = 4;
EdidSerialNumber = 5;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
CurrentOutputResolution = CurrentOutputResolution + joinOffset;
EdidManufacturer = EdidManufacturer + joinOffset;
EdidName = EdidName + joinOffset;
EdidPrefferedTiming = EdidPrefferedTiming + joinOffset;
EdidSerialNumber = EdidSerialNumber + joinOffset;
}
}
}
}

View File

@@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DM;
using Crestron.SimplSharpPro.DM.Endpoints;
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.DM;
namespace PepperDash.Essentials.Bridges
{
public static class DmTxControllerApiExtensions
{
public static void LinkToApi(this DmTxControllerBase tx, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as DmTxControllerJoinMap;
if (joinMap == null)
joinMap = new DmTxControllerJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, tx, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
tx.IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
tx.AnyVideoInput.VideoStatus.VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VideoSyncStatus]);
tx.AnyVideoInput.VideoStatus.VideoResolutionFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentInputResolution]);
//tx.HdcpSupportAllFeedback.LinkInputSig(trilist.UShortInput[joinMap.HdcpSupportCapability]);
bool hdcpTypeSimple;
if (tx.Hardware is DmTx4kX02CBase || tx.Hardware is DmTx4kzX02CBase)
hdcpTypeSimple = false;
else
hdcpTypeSimple = true;
if (tx is ITxRouting)
{
var txR = tx as ITxRouting;
trilist.SetUShortSigAction(joinMap.VideoInput,
new Action<ushort>(i => txR.ExecuteNumericSwitch(i, 0, eRoutingSignalType.Video)));
trilist.SetUShortSigAction(joinMap.AudioInput,
new Action<ushort>(i => txR.ExecuteNumericSwitch(i, 0, eRoutingSignalType.Audio)));
txR.VideoSourceNumericFeedback.LinkInputSig(trilist.UShortInput[joinMap.VideoInput]);
txR.AudioSourceNumericFeedback.LinkInputSig(trilist.UShortInput[joinMap.AudioInput]);
trilist.UShortInput[joinMap.HdcpSupportCapability].UShortValue = (ushort)tx.HdcpSupportCapability;
if(txR.InputPorts[DmPortName.HdmiIn] != null)
{
var inputPort = txR.InputPorts[DmPortName.HdmiIn];
if (tx.Feedbacks["HdmiInHdcpCapability"] != null)
(tx.Feedbacks["HdmiInHdcpCapability"] as IntFeedback).LinkInputSig(trilist.UShortInput[joinMap.Port1HdcpState]);
if (inputPort.ConnectionType == eRoutingPortConnectionType.Hdmi && inputPort.Port != null)
{
var port = inputPort.Port as EndpointHdmiInput;
SetHdcpCapabilityAction(hdcpTypeSimple, port, joinMap.Port1HdcpState, trilist);
}
}
if (txR.InputPorts[DmPortName.HdmiIn1] != null)
{
var inputPort = txR.InputPorts[DmPortName.HdmiIn1];
if (tx.Feedbacks["HdmiIn1HdcpCapability"] != null)
(tx.Feedbacks["HdmiIn1HdcpCapability"] as IntFeedback).LinkInputSig(trilist.UShortInput[joinMap.Port1HdcpState]);
if (inputPort.ConnectionType == eRoutingPortConnectionType.Hdmi && inputPort.Port != null)
{
var port = inputPort.Port as EndpointHdmiInput;
SetHdcpCapabilityAction(hdcpTypeSimple, port, joinMap.Port1HdcpState, trilist);
}
}
if (txR.InputPorts[DmPortName.HdmiIn2] != null)
{
var inputPort = txR.InputPorts[DmPortName.HdmiIn2];
if (tx.Feedbacks["HdmiIn2HdcpCapability"] != null)
(tx.Feedbacks["HdmiIn2HdcpCapability"] as IntFeedback).LinkInputSig(trilist.UShortInput[joinMap.Port1HdcpState]);
if (inputPort.ConnectionType == eRoutingPortConnectionType.Hdmi && inputPort.Port != null)
{
var port = inputPort.Port as EndpointHdmiInput;
SetHdcpCapabilityAction(hdcpTypeSimple, port, joinMap.Port2HdcpState, trilist);
}
}
}
}
static void SetHdcpCapabilityAction(bool hdcpTypeSimple, EndpointHdmiInput port, uint join, BasicTriList trilist)
{
if (hdcpTypeSimple)
{
trilist.SetUShortSigAction(join,
new Action<ushort>(s =>
{
if (s == 0)
{
port.HdcpSupportOff();
}
else if (s > 0)
{
port.HdcpSupportOn();
}
}));
}
else
{
trilist.SetUShortSigAction(join,
new Action<ushort>(s =>
{
port.HdcpCapability = (eHdcpCapabilityType)s;
}));
}
}
public class DmTxControllerJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint VideoSyncStatus { get; set; }
public uint CurrentInputResolution { get; set; }
public uint HdcpSupportCapability { get; set; }
public uint VideoInput { get; set; }
public uint AudioInput { get; set; }
public uint Port1HdcpState { get; set; }
public uint Port2HdcpState { get; set; }
public DmTxControllerJoinMap()
{
// Digital
IsOnline = 1;
VideoSyncStatus = 2;
// Serial
CurrentInputResolution = 1;
// Analog
VideoInput = 1;
AudioInput = 2;
HdcpSupportCapability = 3;
Port1HdcpState = 4;
Port2HdcpState = 5;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
VideoSyncStatus = VideoSyncStatus + joinOffset;
CurrentInputResolution = CurrentInputResolution + joinOffset;
VideoInput = VideoInput + joinOffset;
AudioInput = AudioInput + joinOffset;
HdcpSupportCapability = HdcpSupportCapability + joinOffset;
Port1HdcpState = Port1HdcpState + joinOffset;
Port2HdcpState = Port2HdcpState + joinOffset;
}
}
}
}

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
namespace PepperDash.Essentials.Bridges
{
public static class SamsungDisplayControllerApiExtensions
{
public static void LinkToApi(this PepperDash.Essentials.Core.TwoWayDisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as DisplayControllerJoinMap;
if (joinMap == null)
{
joinMap = new DisplayControllerJoinMap();
}
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, "Linking to lighting Type {0}", displayDevice.GetType().Name.ToString());
var commMonitor = displayDevice as ICommunicationMonitor;
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
// Poewer Off
trilist.SetSigTrueAction(joinMap.PowerOff, () => displayDevice.PowerOff());
displayDevice.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff]);
// Poewer On
trilist.SetSigTrueAction(joinMap.PowerOn, () => displayDevice.PowerOn());
displayDevice.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn]);
// GenericLighitng Actions & FeedBack
// int sceneIndex = 1;
/*
foreach (var scene in displayDevice.LightingScenes)
{
var tempIndex = sceneIndex - 1;
//trilist.SetSigTrueAction((uint)(joinMap.LightingSceneOffset + sceneIndex), () => displayDevice.SelectScene(displayDevice.LightingScenes[tempIndex]));
scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.LightingSceneOffset + sceneIndex)]);
trilist.StringInput[(uint)(joinMap.LightingSceneOffset + sceneIndex)].StringValue = scene.Name;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibilityOffset + sceneIndex)].BoolValue = true;
sceneIndex++;
}
if (displayDevice.GetType().Name.ToString() == "LutronQuantumArea")
{
var lutronDevice = displayDevice as PepperDash.Essentials.Devices.Common.Environment.Lutron.LutronQuantumArea;
lutronDevice.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
trilist.SetStringSigAction(joinMap.IntegrationIdSet, s => lutronDevice.IntegrationId = s);
}
*/
//ApiEisc.Eisc.SetStringSigAction(ApiMap.integrationID, (s) => { lutronLights.IntegrationId = s; });
/*
var lutronLights = displayDevice as PepperDash.Essentials.Devices.Common.Environment.Lutron.LutronQuantumArea;
for (uint i = 1; i <= lightingBase.CircuitCount; i++)
{
var circuit = i;
lightingBase.CircuitNameFeedbacks[circuit - 1].LinkInputSig(trilist.StringInput[joinMap.CircuitNames + circuit]);
lightingBase.CircuitIsCritical[circuit - 1].LinkInputSig(trilist.BooleanInput[joinMap.CircuitIsCritical + circuit]);
lightingBase.CircuitState[circuit - 1].LinkInputSig(trilist.BooleanInput[joinMap.CircuitState + circuit]);
trilist.SetSigTrueAction(joinMap.CircuitCycle + circuit, () => lightingBase.CycleCircuit(circuit - 1));
trilist.SetSigTrueAction(joinMap.CircuitOnCmd + circuit, () => lightingBase.TurnOnCircuit(circuit - 1));
trilist.SetSigTrueAction(joinMap.CircuitOffCmd + circuit, () => lightingBase.TurnOffCircuit(circuit - 1));
}
*/
}
}
public class DisplayControllerJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint PowerOff { get; set; }
public uint PowerOn { get; set; }
public uint SelectScene { get; set; }
public uint LightingSceneOffset { get; set; }
public uint ButtonVisibilityOffset { get; set; }
public uint IntegrationIdSet { get; set; }
public DisplayControllerJoinMap()
{
// Digital
IsOnline = 1;
PowerOff = 1;
PowerOn = 2;
SelectScene = 1;
IntegrationIdSet = 1;
LightingSceneOffset = 10;
ButtonVisibilityOffset = 40;
// Analog
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
PowerOff = PowerOff + joinOffset;
PowerOn = PowerOn + joinOffset;
SelectScene = SelectScene + joinOffset;
LightingSceneOffset = LightingSceneOffset + joinOffset;
ButtonVisibilityOffset = ButtonVisibilityOffset + joinOffset;
}
}
}

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
using PepperDash.Essentials.Core.Routing;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.EthernetCommunication;
using Crestron.SimplSharpPro.CrestronThread;
namespace PepperDash.Essentials {
public class EssentialCommConfig {
public string[] EiscApiIpids;
public EssentialCommCommConnectionConfigs[] CommConnections;
}
public class EssentialCommCommConnectionConfigs {
public uint joinNumber {get; set; }
public EssentialsControlPropertiesConfig control { get; set; }
}
public class EssentialCommsPort {
public IBasicCommunication Comm;
public IntFeedback StatusFeedback;
public BoolFeedback ConnectedFeedback;
public List<EssentialComApiMap> Outputs = new List<EssentialComApiMap>();
public String RxBuffer;
public EssentialCommsPort(EssentialsControlPropertiesConfig config, string keyPrefix) {
Comm = CommFactory.CreateCommForConfig(config, keyPrefix);
// var PortGather = new CommunicationGather(Comm, config.EndOfLineChar);
Comm.TextReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(Communication_TextReceived);
var socket = Comm as ISocketStatus;
StatusFeedback = new IntFeedback(() => { return (int)socket.ClientStatus; });
ConnectedFeedback = new BoolFeedback(() => { return Comm.IsConnected; });
if (socket != null) {
socket.ConnectionChange += new EventHandler<GenericSocketStatusChageEventArgs>(socket_ConnectionChange);
} else {
}
}
void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) {
StatusFeedback.FireUpdate();
ConnectedFeedback.FireUpdate();
if (e.Client.IsConnected) {
// Tasks on connect
} else {
// Cleanup items from this session
}
}
void Communication_TextReceived(object sender, GenericCommMethodReceiveTextArgs args) {
try {
foreach (var Output in Outputs) {
Output.Api.Eisc.StringInput[Output.Join].StringValue = args.Text;
}
}
catch (Exception) {
throw new FormatException(string.Format("ERROR:{0}"));
}
}
}
public class EssentialComm : Device {
public EssentialCommConfig Properties;
public CommunicationGather PortGather { get; private set; }
public List<BridgeApiEisc> Apis {get; set;}
public Dictionary<string, StringFeedback> CommFeedbacks {get; private set; }
public StatusMonitorBase CommunicationMonitor { get; private set; }
public Dictionary<uint, EssentialCommsPort> CommDictionary { get; private set; }
public EssentialComm(string key, string name, JToken properties) : base(key, name) {
Properties = JsonConvert.DeserializeObject<EssentialCommConfig>(properties.ToString());
CommFeedbacks = new Dictionary<string, StringFeedback>();
CommDictionary = new Dictionary<uint, EssentialCommsPort>();
Apis = new List<BridgeApiEisc>();
int commNumber = 1;
foreach (var commConfig in Properties.CommConnections) {
var commPort = new EssentialCommsPort(commConfig.control, string.Format("{0}-{1}", this.Key, commConfig.joinNumber));
CommDictionary.Add(commConfig.joinNumber, commPort);
commNumber++;
}
foreach (var Ipid in Properties.EiscApiIpids) {
var ApiEisc = new BridgeApiEisc(Ipid);
Apis.Add(ApiEisc);
foreach (var commConnection in CommDictionary) {
Debug.Console(2, "Joining Api{0} to comm {1}", Ipid, commConnection.Key);
var tempComm = commConnection.Value;
var tempJoin = (uint)commConnection.Key;
EssentialComApiMap ApiMap = new EssentialComApiMap(ApiEisc, (uint)tempJoin);
tempComm.Outputs.Add(ApiMap);
// Check for ApiMap Overide Values here
ApiEisc.Eisc.SetBoolSigAction(tempJoin, b => {if (b) { tempComm.Comm.Connect(); } else { tempComm.Comm.Disconnect(); }});
ApiEisc.Eisc.SetStringSigAction(tempJoin, s => tempComm.Comm.SendText(s));
tempComm.StatusFeedback.LinkInputSig(ApiEisc.Eisc.UShortInput[tempJoin]);
tempComm.ConnectedFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[tempJoin]);
}
ApiEisc.Eisc.Register();
}
}
public override bool CustomActivate()
{
try {
Debug.Console(2, "Name {0} Activated", this.Name);
return true;
}
catch (Exception e) {
Debug.Console(0, "Bridge {0}", e);
return false;
}
}
}
public class EssentialComApiMap {
public uint Join;
public BridgeApiEisc Api;
public uint connectJoin;
public EssentialComApiMap(BridgeApiEisc api, uint join) {
Join = join;
Api = api;
}
}
}

View File

@@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.DM;
using PepperDash.Core;
using PepperDash.Essentials.Core.Routing;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.EthernetCommunication;
using Crestron.SimplSharpPro.DM;
namespace PepperDash.Essentials {
public class EssentialDM : PepperDash.Core.Device {
public EssentialDMProperties Properties;
public List<BridgeApiEisc> BridgeApiEiscs;
private PepperDash.Essentials.DM.DmChassisController DmSwitch;
private EssentialDMApiMap ApiMap = new EssentialDMApiMap();
public EssentialDM(string key, string name, JToken properties)
: base(key, name) {
Properties = JsonConvert.DeserializeObject<EssentialDMProperties>(properties.ToString());
}
public override bool CustomActivate() {
// Create EiscApis
try {
foreach (var device in DeviceManager.AllDevices) {
if (device.Key == this.Properties.connectionDeviceKey) {
Debug.Console(2, "deviceKey {0} Matches", device.Key);
DmSwitch = DeviceManager.GetDeviceForKey(device.Key) as PepperDash.Essentials.DM.DmChassisController;
}
else {
Debug.Console(2, "deviceKey {0} doesn't match", device.Key);
}
}
if (Properties.EiscApiIpids != null) {
foreach (string Ipid in Properties.EiscApiIpids) {
var ApiEisc = new BridgeApiEisc(Ipid);
for (uint x = 1; x <= DmSwitch.Chassis.NumberOfInputs;x++ ) {
uint tempX = x;
Debug.Console(2, "Creating EiscActions {0}", tempX);
ApiEisc.Eisc.SetUShortSigAction(ApiMap.OutputVideoRoutes[tempX], u => DmSwitch.ExecuteSwitch(u, tempX, eRoutingSignalType.Video));
ApiEisc.Eisc.SetUShortSigAction(ApiMap.OutputAudioRoutes[tempX], u => DmSwitch.ExecuteSwitch(u, tempX, eRoutingSignalType.Audio));
if (DmSwitch.TxDictionary.ContainsKey(tempX)) {
Debug.Console(2, "Creating Tx Feedbacks {0}", tempX);
var TxKey = DmSwitch.TxDictionary[tempX];
var TxDevice = DeviceManager.GetDeviceForKey(TxKey) as DmTxControllerBase;
TxDevice.IsOnline.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.TxOnlineStatus[tempX]]);
TxDevice.AnyVideoInput.VideoStatus.VideoSyncFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.TxVideoSyncStatus[tempX]]);
ApiEisc.Eisc.SetUShortSigAction((ApiMap.HdcpSupport[tempX]), u => TxDevice.SetHdcpSupportAll((ePdtHdcpSupport)(u)));
TxDevice.HdcpSupportAllFeedback.LinkInputSig(ApiEisc.Eisc.UShortInput[ApiMap.HdcpSupport[tempX]]);
ApiEisc.Eisc.UShortInput[ApiMap.HdcpSupportCapability[tempX]].UShortValue = TxDevice.HdcpSupportCapability;
}
else {
DmSwitch.VideoInputSyncFeedbacks[tempX].LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.TxVideoSyncStatus[tempX]]);
}
if (DmSwitch.RxDictionary.ContainsKey(tempX)) {
Debug.Console(2, "Creating Rx Feedbacks {0}", tempX);
var RxKey = DmSwitch.RxDictionary[tempX];
var RxDevice = DeviceManager.GetDeviceForKey(RxKey) as DmRmcControllerBase;
RxDevice.IsOnline.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.RxOnlineStatus[tempX]]);
}
// DmSwitch.InputEndpointOnlineFeedbacks[(ushort)tempOutputNum].LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.OutputVideoRoutes[tempOutputNum]]);
DmSwitch.VideoOutputFeedbacks[(ushort)tempX].LinkInputSig(ApiEisc.Eisc.UShortInput[ApiMap.OutputVideoRoutes[tempX]]);
DmSwitch.AudioOutputFeedbacks[(ushort)tempX].LinkInputSig(ApiEisc.Eisc.UShortInput[ApiMap.OutputAudioRoutes[tempX]]);
DmSwitch.InputNameFeedbacks[(ushort)tempX].LinkInputSig(ApiEisc.Eisc.StringInput[ApiMap.InputNames[tempX]]);
DmSwitch.OutputNameFeedbacks[(ushort)tempX].LinkInputSig(ApiEisc.Eisc.StringInput[ApiMap.OutputNames[tempX]]);
DmSwitch.OutputRouteNameFeedbacks[(ushort)tempX].LinkInputSig(ApiEisc.Eisc.StringInput[ApiMap.OutputRouteNames[tempX]]);
}
DmSwitch.IsOnline.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.ChassisOnline]);
ApiEisc.Eisc.Register();
}
}
Debug.Console(2, "Name {0} Activated", this.Name);
return true;
}
catch (Exception e) {
Debug.Console(2, "BRidge {0}", e);
return false;
}
}
}
public class EssentialDMProperties {
public string connectionDeviceKey;
public string[] EiscApiIpids;
}
public class EssentialDMApiMap {
public ushort ChassisOnline = 11;
public Dictionary<uint, ushort> OutputVideoRoutes;
public Dictionary<uint, ushort> OutputAudioRoutes;
public Dictionary<uint, ushort> TxOnlineStatus;
public Dictionary<uint, ushort> RxOnlineStatus;
public Dictionary<uint, ushort> TxVideoSyncStatus;
public Dictionary<uint, ushort> InputNames;
public Dictionary<uint, ushort> OutputNames;
public Dictionary<uint, ushort> OutputRouteNames;
public Dictionary<uint, ushort> HdcpSupport;
public Dictionary<uint, ushort> HdcpSupportCapability;
public EssentialDMApiMap() {
OutputVideoRoutes = new Dictionary<uint, ushort>();
OutputAudioRoutes = new Dictionary<uint, ushort>();
TxOnlineStatus = new Dictionary<uint, ushort>();
RxOnlineStatus = new Dictionary<uint, ushort>();
TxVideoSyncStatus = new Dictionary<uint, ushort>();
InputNames = new Dictionary<uint, ushort>();
OutputNames = new Dictionary<uint, ushort>();
OutputRouteNames = new Dictionary<uint, ushort>();
HdcpSupport = new Dictionary<uint, ushort>();
HdcpSupportCapability = new Dictionary<uint, ushort>();
for (uint x = 1; x <= 200; x++) {
// Debug.Console(0, "Init Value {0}", x);
uint tempNum = x;
HdcpSupportCapability[tempNum] = (ushort)(tempNum + 1200);
HdcpSupport[tempNum] = (ushort)(tempNum + 1000);
OutputVideoRoutes[tempNum] = (ushort)(tempNum + 100);
OutputAudioRoutes[tempNum] = (ushort)(tempNum + 300);
TxOnlineStatus[tempNum] = (ushort)(tempNum + 500);
RxOnlineStatus[tempNum] = (ushort)(tempNum + 700);
TxVideoSyncStatus[tempNum] = (ushort)(tempNum + 100);
InputNames[tempNum] = (ushort)(tempNum + 100);
OutputNames[tempNum] = (ushort)(tempNum + 300);
OutputRouteNames[tempNum] = (ushort)(tempNum + 2000);
}
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.DM;
using PepperDash.Core;
using PepperDash.Essentials.Core.Routing;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.EthernetCommunication;
using Crestron.SimplSharpPro.DM;
namespace PepperDash.Essentials {
public class EssentialDsp : PepperDash.Core.Device {
public EssentialDspProperties Properties;
public List<BridgeApiEisc> BridgeApiEiscs;
private PepperDash.Essentials.Devices.Common.DSP.QscDsp Dsp;
private EssentialDspApiMap ApiMap = new EssentialDspApiMap();
public EssentialDsp(string key, string name, JToken properties)
: base(key, name) {
Properties = JsonConvert.DeserializeObject<EssentialDspProperties>(properties.ToString());
}
public override bool CustomActivate() {
// Create EiscApis
try
{
ICommunicationMonitor comm = null;
foreach (var device in DeviceManager.AllDevices)
{
if (device.Key == this.Properties.connectionDeviceKey)
{
if (!(device is ICommunicationMonitor))
{
comm = device as ICommunicationMonitor;
}
Debug.Console(2, "deviceKey {0} Matches", device.Key);
Dsp = DeviceManager.GetDeviceForKey(device.Key) as PepperDash.Essentials.Devices.Common.DSP.QscDsp;
break;
}
else
{
Debug.Console(2, "deviceKey {0} doesn't match", device.Key);
}
}
if (Properties.EiscApiIpids != null && Dsp != null)
{
foreach (string Ipid in Properties.EiscApiIpids)
{
var ApiEisc = new BridgeApiEisc(Ipid);
Debug.Console(2, "Connecting EiscApi {0} to {1}", ApiEisc.Ipid, Dsp.Name);
ushort x = 1;
if (comm != null)
{
comm.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.Online]);
}
foreach (var channel in Dsp.LevelControlPoints)
{
//var QscChannel = channel.Value as PepperDash.Essentials.Devices.Common.DSP.QscDspLevelControl;
Debug.Console(2, "QscChannel {0} connect", x);
var genericChannel = channel.Value as IBasicVolumeWithFeedback;
if (channel.Value.Enabled)
{
ApiEisc.Eisc.StringInput[ApiMap.channelName[x]].StringValue = channel.Value.LevelCustomName;
ApiEisc.Eisc.UShortInput[ApiMap.channelType[x]].UShortValue = (ushort)channel.Value.Type;
genericChannel.MuteFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.channelMuteToggle[x]]);
genericChannel.VolumeLevelFeedback.LinkInputSig(ApiEisc.Eisc.UShortInput[ApiMap.channelVolume[x]]);
ApiEisc.Eisc.SetSigTrueAction(ApiMap.channelMuteToggle[x], () => genericChannel.MuteToggle());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.channelMuteOn[x], () => genericChannel.MuteOn());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.channelMuteOff[x], () => genericChannel.MuteOff());
ApiEisc.Eisc.SetBoolSigAction(ApiMap.channelVolumeUp[x], b => genericChannel.VolumeUp(b));
ApiEisc.Eisc.SetBoolSigAction(ApiMap.channelVolumeDown[x], b => genericChannel.VolumeDown(b));
ApiEisc.Eisc.SetUShortSigAction(ApiMap.channelVolume[x], u => genericChannel.SetVolume(u));
ApiEisc.Eisc.SetStringSigAction(ApiMap.presetString, s => Dsp.RunPreset(s));
}
x++;
}
x = 1;
foreach (var preset in Dsp.PresetList)
{
ApiEisc.Eisc.StringInput[ApiMap.presets[x]].StringValue = preset.label;
ApiEisc.Eisc.SetSigTrueAction(ApiMap.presets[x], () => Dsp.RunPresetNumber(x));
x++;
}
foreach (var dialer in Dsp.Dialers)
{
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad0, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num0));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad1, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num1));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad2, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num2));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad3, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num3));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad4, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num4));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad5, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num5));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad6, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num6));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad7, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num7));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad8, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num8));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Keypad9, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num9));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.KeypadStar, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Star));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.KeypadPound, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Pound));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.KeypadClear, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Clear));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.KeypadBackspace, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Backspace));
ApiEisc.Eisc.SetSigTrueAction(ApiMap.Dial, () => dialer.Value.Dial());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.DoNotDisturbToggle, () => dialer.Value.DoNotDisturbToggle());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.DoNotDisturbOn, () => dialer.Value.DoNotDisturbOn());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.DoNotDisturbOff, () => dialer.Value.DoNotDisturbOff());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.AutoAnswerToggle, () => dialer.Value.AutoAnswerToggle());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.AutoAnswerOn, () => dialer.Value.AutoAnswerOn());
ApiEisc.Eisc.SetSigTrueAction(ApiMap.AutoAnswerOff, () => dialer.Value.AutoAnswerOff());
dialer.Value.DoNotDisturbFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.DoNotDisturbToggle]);
dialer.Value.DoNotDisturbFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.DoNotDisturbOn]);
dialer.Value.DoNotDisturbFeedback.LinkComplementInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.DoNotDisturbOff]);
dialer.Value.AutoAnswerFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.AutoAnswerToggle]);
dialer.Value.AutoAnswerFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.AutoAnswerOn]);
dialer.Value.AutoAnswerFeedback.LinkComplementInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.AutoAnswerOff]);
dialer.Value.OffHookFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.Dial]);
dialer.Value.DialStringFeedback.LinkInputSig(ApiEisc.Eisc.StringInput[ApiMap.DialString]);
}
}
}
Debug.Console(2, "Name {0} Activated", this.Name);
return true;
}
catch (Exception e) {
Debug.Console(0, "Bridge {0}", e);
return false;
}
}
}
public class EssentialDspProperties {
public string connectionDeviceKey;
public string[] EiscApiIpids;
}
public class EssentialDspApiMap {
public ushort Online = 1;
public ushort presetString = 2000;
public Dictionary<uint, ushort> channelMuteToggle;
public Dictionary<uint, ushort> channelMuteOn;
public Dictionary<uint, ushort> channelMuteOff;
public Dictionary<uint, ushort> channelVolume;
public Dictionary<uint, ushort> channelType;
public Dictionary<uint, ushort> channelName;
public Dictionary<uint, ushort> channelVolumeUp;
public Dictionary<uint, ushort> channelVolumeDown;
public Dictionary<uint, ushort> presets;
public ushort DialString = 3100;
public ushort Keypad0 = 3110;
public ushort Keypad1 = 3111;
public ushort Keypad2 = 3112;
public ushort Keypad3 = 3113;
public ushort Keypad4 = 3114;
public ushort Keypad5 = 3115;
public ushort Keypad6 = 3116;
public ushort Keypad7 = 3117;
public ushort Keypad8 = 3118;
public ushort Keypad9 = 3119;
public ushort KeypadStar = 3120;
public ushort KeypadPound = 3121;
public ushort KeypadClear = 3122;
public ushort KeypadBackspace = 3123;
public ushort Dial = 3124;
public ushort DoNotDisturbToggle = 3132;
public ushort DoNotDisturbOn = 3133;
public ushort DoNotDisturbOff = 3134;
public ushort AutoAnswerToggle = 3127;
public ushort AutoAnswerOn = 3125;
public ushort AutoAnswerOff = 3126;
public EssentialDspApiMap() {
channelMuteToggle = new Dictionary<uint, ushort>();
channelMuteOn = new Dictionary<uint, ushort>();
channelMuteOff = new Dictionary<uint, ushort>();
channelVolume = new Dictionary<uint, ushort>();
channelName = new Dictionary<uint, ushort>();
channelType = new Dictionary<uint, ushort>();
presets = new Dictionary<uint, ushort>();
channelVolumeUp = new Dictionary<uint, ushort>();
channelVolumeDown = new Dictionary<uint, ushort>();
for (uint x = 1; x <= 100; x++) {
uint tempNum = x;
presets[tempNum] = (ushort)(tempNum + 100);
channelMuteToggle[tempNum] = (ushort)(tempNum + 400);
channelMuteOn[tempNum] = (ushort)(tempNum + 600);
channelMuteOff[tempNum] = (ushort)(tempNum + 800);
channelVolume[tempNum] = (ushort)(tempNum + 200);
channelName[tempNum] = (ushort)(tempNum + 200);
channelType[tempNum] = (ushort)(tempNum + 400);
channelVolumeUp[tempNum] = (ushort)(tempNum + 1000);
channelVolumeDown[tempNum] = (ushort)(tempNum + 1200);
}
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.DM;
using PepperDash.Core;
using PepperDash.Essentials.Core.Routing;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.EthernetCommunication;
using Crestron.SimplSharpPro.DM;
namespace PepperDash.Essentials
{
public class EssentialsTVOne : PepperDash.Core.Device
{
public EssentialTVOneProperties Properties;
public List<BridgeApiEisc> BridgeApiEiscs;
private PepperDash.Essentials.Devices.Common.TVOneCorio TVOneCorio;
private EssentialsTVOneApiMap ApiMap = new EssentialsTVOneApiMap();
public EssentialsTVOne(string key, string name, JToken properties)
: base(key, name)
{
Properties = JsonConvert.DeserializeObject<EssentialTVOneProperties>(properties.ToString());
}
public override bool CustomActivate() {
// Create EiscApis
try
{
foreach (var device in DeviceManager.AllDevices)
{
if (device.Key == this.Properties.connectionDeviceKey)
{
Debug.Console(2, "deviceKey {0} Matches", device.Key);
TVOneCorio = DeviceManager.GetDeviceForKey(device.Key) as PepperDash.Essentials.Devices.Common.TVOneCorio;
break;
}
else
{
Debug.Console(2, "deviceKey {0} doesn't match", device.Key);
}
}
if (Properties.EiscApiIpids != null && TVOneCorio != null)
{
foreach (string Ipid in Properties.EiscApiIpids)
{
var ApiEisc = new BridgeApiEisc(Ipid);
Debug.Console(2, "Connecting EiscApi {0} to {1}", ApiEisc.Ipid, TVOneCorio.Name);
ushort x = 1;
TVOneCorio.OnlineFeedback.LinkInputSig(ApiEisc.Eisc.BooleanInput[ApiMap.Online]);
ApiEisc.Eisc.SetUShortSigAction(ApiMap.CallPreset, u => TVOneCorio.CallPreset(u));
TVOneCorio.PresetFeedback.LinkInputSig(ApiEisc.Eisc.UShortInput[ApiMap.PresetFeedback]);
}
}
Debug.Console(2, "Name {0} Activated", this.Name);
return true;
}
catch (Exception e) {
Debug.Console(0, "Bridge {0}", e);
return false;
}
}
}
public class EssentialTVOneProperties
{
public string connectionDeviceKey;
public string[] EiscApiIpids;
}
public class EssentialsTVOneApiMap
{
public ushort CallPreset = 1;
public ushort PresetFeedback = 1;
public ushort Online = 1;
public EssentialsTVOneApiMap()
{
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
namespace PepperDash.Essentials.Bridges
{
public static class GenericLightingApiExtensions
{
public static void LinkToApi(this PepperDash.Essentials.Core.Lighting.LightingBase lightingDevice, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as GenericLightingJoinMap;
if (joinMap == null)
joinMap = new GenericLightingJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, "Linking to lighting Type {0}", lightingDevice.GetType().Name.ToString());
// GenericLighitng Actions & FeedBack
trilist.SetUShortSigAction(joinMap.SelectScene, u => {if(u > 0) { lightingDevice.SelectScene(lightingDevice.LightingScenes[u-1]);}});
int sceneIndex = 1;
foreach (var scene in lightingDevice.LightingScenes)
{
var tempIndex = sceneIndex - 1;
trilist.SetSigTrueAction((uint)(joinMap.LightingSceneOffset + sceneIndex), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[tempIndex]));
scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.LightingSceneOffset + sceneIndex)]);
trilist.StringInput[(uint)(joinMap.LightingSceneOffset + sceneIndex)].StringValue = scene.Name;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibilityOffset + sceneIndex)].BoolValue = true;
sceneIndex++;
}
if (lightingDevice.GetType().Name.ToString() == "LutronQuantumArea")
{
var lutronDevice = lightingDevice as PepperDash.Essentials.Devices.Common.Environment.Lutron.LutronQuantumArea;
lutronDevice.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
trilist.SetStringSigAction(joinMap.IntegrationIdSet, s => lutronDevice.IntegrationId = s);
}
//ApiEisc.Eisc.SetStringSigAction(ApiMap.integrationID, (s) => { lutronLights.IntegrationId = s; });
/*
var lutronLights = lightingDevice as PepperDash.Essentials.Devices.Common.Environment.Lutron.LutronQuantumArea;
for (uint i = 1; i <= lightingBase.CircuitCount; i++)
{
var circuit = i;
lightingBase.CircuitNameFeedbacks[circuit - 1].LinkInputSig(trilist.StringInput[joinMap.CircuitNames + circuit]);
lightingBase.CircuitIsCritical[circuit - 1].LinkInputSig(trilist.BooleanInput[joinMap.CircuitIsCritical + circuit]);
lightingBase.CircuitState[circuit - 1].LinkInputSig(trilist.BooleanInput[joinMap.CircuitState + circuit]);
trilist.SetSigTrueAction(joinMap.CircuitCycle + circuit, () => lightingBase.CycleCircuit(circuit - 1));
trilist.SetSigTrueAction(joinMap.CircuitOnCmd + circuit, () => lightingBase.TurnOnCircuit(circuit - 1));
trilist.SetSigTrueAction(joinMap.CircuitOffCmd + circuit, () => lightingBase.TurnOffCircuit(circuit - 1));
}
*/
}
}
public class GenericLightingJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint SelectScene { get; set; }
public uint LightingSceneOffset { get; set; }
public uint ButtonVisibilityOffset { get; set; }
public uint IntegrationIdSet { get; set; }
public GenericLightingJoinMap()
{
// Digital
IsOnline = 1;
SelectScene = 1;
IntegrationIdSet = 1;
LightingSceneOffset = 10;
ButtonVisibilityOffset = 40;
// Analog
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
SelectScene = SelectScene + joinOffset;
LightingSceneOffset = LightingSceneOffset + joinOffset;
ButtonVisibilityOffset = ButtonVisibilityOffset + joinOffset;
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.CrestronIO;
namespace PepperDash.Essentials.Bridges
{
public static class GenericRelayDeviceApiExtensions
{
public static void LinkToApi(this GenericRelayDevice relay, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as GenericRelayControllerJoinMap;
if (joinMap == null)
joinMap = new GenericRelayControllerJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
if (relay.RelayOutput == null)
{
Debug.Console(1, relay, "Unable to link device '{0}'. Relay is null", relay.Key);
return;
}
Debug.Console(1, relay, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
trilist.SetBoolSigAction(joinMap.Relay, new Action<bool>(b =>
{
if (b)
relay.CloseRelay();
else
relay.OpenRelay();
}));
// feedback for relay state
relay.OutputIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Relay]);
}
}
public class GenericRelayControllerJoinMap : JoinMapBase
{
//Digital
public uint Relay { get; set; }
public GenericRelayControllerJoinMap()
{
Relay = 1;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
Relay = Relay + joinOffset;
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Bridges
{
public static class IBasicCommunicationApiExtensions
{
public static void LinkToApi(this GenericComm comm, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as IBasicCommunicationJoinMap;
if (joinMap == null)
joinMap = new IBasicCommunicationJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
if (comm.CommPort == null)
{
Debug.Console(1, comm, "Unable to link device '{0}'. CommPort is null", comm.Key);
return;
}
Debug.Console(1, comm, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
// this is a permanent event handler. This cannot be -= from event
comm.CommPort.TextReceived += (s, a) => trilist.SetString(joinMap.TextReceived, a.Text);
trilist.SetStringSigAction(joinMap.SendText, new Action<string>(s => comm.CommPort.SendText(s)));
trilist.SetStringSigAction(joinMap.SetPortConfig + 1, new Action<string>(s => comm.SetPortConfig(s)));
var sComm = comm.CommPort as ISocketStatus;
if (sComm != null)
{
sComm.ConnectionChange += (s, a) =>
{
trilist.SetUshort(joinMap.Status, (ushort)(a.Client.ClientStatus));
trilist.SetBool(joinMap.Connected, a.Client.ClientStatus ==
Crestron.SimplSharp.CrestronSockets.SocketStatus.SOCKET_STATUS_CONNECTED);
};
trilist.SetBoolSigAction(joinMap.Connect, new Action<bool>(b =>
{
if (b)
{
sComm.Connect();
}
else
{
sComm.Disconnect();
}
}));
}
}
public class IBasicCommunicationJoinMap : JoinMapBase
{
//Digital
public uint Connect { get; set; }
public uint Connected { get; set; }
//Analog
public uint Status { get; set; }
// Serial
public uint TextReceived { get; set; }
public uint SendText { get; set; }
public uint SetPortConfig { get; set; }
public IBasicCommunicationJoinMap()
{
TextReceived = 1;
SendText = 1;
SetPortConfig = 2;
Connect = 1;
Connected = 1;
Status = 1;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
TextReceived = TextReceived + joinOffset;
SendText = SendText + joinOffset;
SetPortConfig = SetPortConfig + joinOffset;
Connect = Connect + joinOffset;
Connected = Connected + joinOffset;
Status = Status + joinOffset;
}
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core.CrestronIO;
namespace PepperDash.Essentials.Bridges
{
public static class IDigitalInputApiExtenstions
{
public static void LinkToApi(this IDigitalInput input, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as IDigitalInputApiJoinMap;
if (joinMap == null)
joinMap = new IDigitalInputApiJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
try
{
Debug.Console(1, input as Device, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
// Link feedback for input state
input.InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState]);
}
catch (Exception e)
{
Debug.Console(1, input as Device, "Unable to link device '{0}'. Input is null", (input as Device).Key);
Debug.Console(1, input as Device, "Error: {0}", e);
return;
}
}
}
public class IDigitalInputApiJoinMap : JoinMapBase
{
//Digital
public uint InputState { get; set; }
public IDigitalInputApiJoinMap()
{
InputState = 1;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
InputState = InputState + joinOffset;
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Bridges
{
public static class JoinMapHelper
{
/// <summary>
/// Attempts to get the join map from config
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static JoinMapBase GetJoinMapForDevice(string joinMapKey)
{
if (!string.IsNullOrEmpty(joinMapKey))
return null;
// FUTURE TODO: Get the join map from the ConfigReader.ConfigObject
return null;
}
}
public abstract class JoinMapBase
{
/// <summary>
/// Modifies all the join numbers by adding the offset. This should never be called twice
/// </summary>
/// <param name="joinStart"></param>
public abstract void OffsetJoinNumbers(uint joinStart);
}
}

View File

@@ -0,0 +1,224 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Devices.Common.DSP;
namespace PepperDash.Essentials.Bridges
{
public static class QscDspDeviceApiExtensions
{
public static void LinkToApi(this QscDsp DspDevice, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as QscDspDeviceJoinMap;
if (joinMap == null)
joinMap = new QscDspDeviceJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, DspDevice, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
ushort x = 1;
var comm = DspDevice as ICommunicationMonitor;
DspDevice.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
foreach (var channel in DspDevice.LevelControlPoints)
{
//var QscChannel = channel.Value as PepperDash.Essentials.Devices.Common.DSP.QscDspLevelControl;
Debug.Console(2, "QscChannel {0} connect", x);
var genericChannel = channel.Value as IBasicVolumeWithFeedback;
if (channel.Value.Enabled)
{
trilist.StringInput[joinMap.ChannelName + x].StringValue = channel.Value.LevelCustomName;
trilist.UShortInput[joinMap.ChannelType + x].UShortValue = (ushort)channel.Value.Type;
genericChannel.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ChannelMuteToggle + x]);
genericChannel.VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.ChannelVolume + x]);
trilist.SetSigTrueAction(joinMap.ChannelMuteToggle + x, () => genericChannel.MuteToggle());
trilist.SetSigTrueAction(joinMap.ChannelMuteOn + x, () => genericChannel.MuteOn());
trilist.SetSigTrueAction(joinMap.ChannelMuteOff + x, () => genericChannel.MuteOff());
trilist.SetBoolSigAction(joinMap.ChannelVolumeUp + x, b => genericChannel.VolumeUp(b));
trilist.SetBoolSigAction(joinMap.ChannelVolumeDown + x, b => genericChannel.VolumeDown(b));
trilist.SetUShortSigAction(joinMap.ChannelVolume + x, u => genericChannel.SetVolume(u));
}
x++;
}
x = 1;
trilist.SetStringSigAction(joinMap.PresetStringCmd, s => DspDevice.RunPreset(s));
foreach (var preset in DspDevice.PresetList)
{
trilist.StringInput[joinMap.Presets + x].StringValue = preset.label;
trilist.SetSigTrueAction(joinMap.Presets + x, () => DspDevice.RunPresetNumber(x));
x++;
}
foreach (var dialer in DspDevice.Dialers)
{
trilist.SetSigTrueAction(joinMap.Keypad0, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num0));
trilist.SetSigTrueAction(joinMap.Keypad1, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num1));
trilist.SetSigTrueAction(joinMap.Keypad2, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num2));
trilist.SetSigTrueAction(joinMap.Keypad3, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num3));
trilist.SetSigTrueAction(joinMap.Keypad4, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num4));
trilist.SetSigTrueAction(joinMap.Keypad5, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num5));
trilist.SetSigTrueAction(joinMap.Keypad6, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num6));
trilist.SetSigTrueAction(joinMap.Keypad7, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num7));
trilist.SetSigTrueAction(joinMap.Keypad8, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num8));
trilist.SetSigTrueAction(joinMap.Keypad9, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Num9));
trilist.SetSigTrueAction(joinMap.KeypadStar, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Star));
trilist.SetSigTrueAction(joinMap.KeypadPound, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Pound));
trilist.SetSigTrueAction(joinMap.KeypadClear, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Clear));
trilist.SetSigTrueAction(joinMap.KeypadBackspace, () => dialer.Value.SendKeypad(PepperDash.Essentials.Devices.Common.DSP.QscDspDialer.eKeypadKeys.Backspace));
trilist.SetSigTrueAction(joinMap.Dial, () => dialer.Value.Dial());
trilist.SetSigTrueAction(joinMap.DoNotDisturbToggle, () => dialer.Value.DoNotDisturbToggle());
trilist.SetSigTrueAction(joinMap.DoNotDisturbOn, () => dialer.Value.DoNotDisturbOn());
trilist.SetSigTrueAction(joinMap.DoNotDisturbOff, () => dialer.Value.DoNotDisturbOff());
trilist.SetSigTrueAction(joinMap.AutoAnswerToggle, () => dialer.Value.AutoAnswerToggle());
trilist.SetSigTrueAction(joinMap.AutoAnswerOn, () => dialer.Value.AutoAnswerOn());
trilist.SetSigTrueAction(joinMap.AutoAnswerOff, () => dialer.Value.AutoAnswerOff());
dialer.Value.DoNotDisturbFeedback.LinkInputSig(trilist.BooleanInput[joinMap.DoNotDisturbToggle]);
dialer.Value.DoNotDisturbFeedback.LinkInputSig(trilist.BooleanInput[joinMap.DoNotDisturbOn]);
dialer.Value.DoNotDisturbFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DoNotDisturbOff]);
dialer.Value.AutoAnswerFeedback.LinkInputSig(trilist.BooleanInput[joinMap.AutoAnswerToggle]);
dialer.Value.AutoAnswerFeedback.LinkInputSig(trilist.BooleanInput[joinMap.AutoAnswerOn]);
dialer.Value.AutoAnswerFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.AutoAnswerOff]);
dialer.Value.OffHookFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Dial]);
dialer.Value.DialStringFeedback.LinkInputSig(trilist.StringInput[joinMap.DialStringCmd]);
}
}
}
public class QscDspDeviceJoinMap : JoinMapBase
{
public uint IsOnline { get; set; }
public uint PresetStringCmd { get; set; }
public uint ChannelMuteToggle { get; set; }
public uint ChannelMuteOn { get; set; }
public uint ChannelMuteOff { get; set; }
public uint ChannelVolume { get; set; }
public uint ChannelType { get; set; }
public uint ChannelName { get; set; }
public uint ChannelVolumeUp { get; set; }
public uint ChannelVolumeDown { get; set; }
public uint Presets { get; set; }
public uint DialStringCmd { get; set; }
public uint Keypad0 { get; set; }
public uint Keypad1 { get; set; }
public uint Keypad2 { get; set; }
public uint Keypad3 { get; set; }
public uint Keypad4 { get; set; }
public uint Keypad5 { get; set; }
public uint Keypad6 { get; set; }
public uint Keypad7 { get; set; }
public uint Keypad8 { get; set; }
public uint Keypad9 { get; set; }
public uint KeypadStar { get; set; }
public uint KeypadPound { get; set; }
public uint KeypadClear { get; set; }
public uint KeypadBackspace { get; set; }
public uint Dial { get; set; }
public uint DoNotDisturbToggle { get; set; }
public uint DoNotDisturbOn { get; set; }
public uint DoNotDisturbOff { get; set; }
public uint AutoAnswerToggle { get; set; }
public uint AutoAnswerOn { get; set; }
public uint AutoAnswerOff { get; set; }
public uint CallPreset { get; set; }
public uint PresetFeedback { get; set; }
public QscDspDeviceJoinMap()
{
// Arrays
ChannelName = 200;
ChannelMuteToggle = 400;
ChannelMuteOn = 600;
ChannelMuteOff = 800;
ChannelVolume = 200;
ChannelVolumeUp = 1000;
ChannelVolumeDown = 1200;
ChannelType = 400;
Presets = 100;
// SIngleJoins
IsOnline = 1;
PresetStringCmd = 2000;
DialStringCmd = 3100;
Keypad0 = 3110;
Keypad1 = 3111;
Keypad2 = 3112;
Keypad3 = 3113;
Keypad4 = 3114;
Keypad5 = 3115;
Keypad6 = 3116;
Keypad7 = 3117;
Keypad8 = 3118;
Keypad9 = 3119;
KeypadStar = 3120;
KeypadPound = 3121;
KeypadClear = 3122;
KeypadBackspace = 3123;
DoNotDisturbToggle = 3132;
DoNotDisturbOn = 3133;
DoNotDisturbOff = 3134;
AutoAnswerToggle = 3127;
AutoAnswerOn = 3125;
AutoAnswerOff = 3126;
Dial = 3124;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
ChannelName = ChannelName + joinOffset;
ChannelMuteToggle = ChannelMuteToggle + joinOffset;
ChannelMuteOn = ChannelMuteOn + joinOffset;
ChannelMuteOff = ChannelMuteOff + joinOffset;
ChannelVolume = ChannelVolume + joinOffset;
ChannelVolumeUp = ChannelVolumeUp + joinOffset;
ChannelVolumeDown = ChannelVolumeDown + joinOffset;
ChannelType = ChannelType + joinOffset;
Presets = Presets + joinOffset;
IsOnline = IsOnline + joinOffset;
PresetStringCmd = PresetStringCmd + joinOffset;
DialStringCmd = DialStringCmd + joinOffset;
Keypad0 = Keypad0 + joinOffset;
Keypad1 = Keypad1 + joinOffset;
Keypad2 = Keypad2 + joinOffset;
Keypad3 = Keypad3 + joinOffset;
Keypad4 = Keypad4 + joinOffset;
Keypad5 = Keypad5 + joinOffset;
Keypad6 = Keypad6 + joinOffset;
Keypad7 = Keypad7 + joinOffset;
Keypad8 = Keypad8 + joinOffset;
Keypad9 = Keypad9 + joinOffset;
KeypadStar = KeypadStar + joinOffset;
KeypadPound = KeypadPound + joinOffset;
KeypadClear = KeypadClear + joinOffset;
KeypadBackspace = KeypadBackspace + joinOffset;
DoNotDisturbToggle = DoNotDisturbToggle + joinOffset;
DoNotDisturbOn = DoNotDisturbOn + joinOffset;
DoNotDisturbOff = DoNotDisturbOff + joinOffset;
AutoAnswerToggle = AutoAnswerToggle + joinOffset;
AutoAnswerOn = AutoAnswerOn + joinOffset;
AutoAnswerOff = AutoAnswerOff + joinOffset;
Dial = Dial + joinOffset;
}
}
}

View File

@@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.Diagnostics;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Monitoring;
namespace PepperDash.Essentials.Bridges
{
public static class SystemMonitorBridge
{
public static void LinkToApi(this SystemMonitorController systemMonitorController, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as SystemMonitorJoinMap;
if (joinMap == null)
joinMap = new SystemMonitorJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
//Debug.Console(1, systemMonitorController, "Linking API starting at join: {0}", joinStart);
systemMonitorController.TimeZoneFeedback.LinkInputSig(trilist.UShortInput[joinMap.TimeZone]);
//trilist.SetUShortSigAction(joinMap.TimeZone, new Action<ushort>(u => systemMonitorController.SetTimeZone(u)));
systemMonitorController.TimeZoneTextFeedback.LinkInputSig(trilist.StringInput[joinMap.TimeZoneName]);
systemMonitorController.IOControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.IOControllerVersion]);
systemMonitorController.SnmpVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.SnmpAppVersion]);
systemMonitorController.BACnetAppVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.BACnetAppVersion]);
systemMonitorController.ControllerVersionFeedback.LinkInputSig(trilist.StringInput[joinMap.ControllerVersion]);
// iterate the program status feedback collection and map all the joins
var programSlotJoinStart = joinMap.ProgramStartJoin;
foreach (var p in systemMonitorController.ProgramStatusFeedbackCollection)
{
// TODO: link feedbacks for each program slot
var programNumber = p.Value.Program.Number;
//Debug.Console(1, systemMonitorController, "Linking API for Program Slot: {0} starting at join: {1}", programNumber, programSlotJoinStart);
trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStart, new Action<bool>
(b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Start));
p.Value.ProgramStartedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStart]);
trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramStop, new Action<bool>
(b => SystemMonitor.ProgramCollection[programNumber].OperatingState = eProgramOperatingState.Stop));
p.Value.ProgramStoppedFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramStop]);
trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramRegister, new Action<bool>
(b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Register));
p.Value.ProgramRegisteredFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramRegister]);
trilist.SetBoolSigAction(programSlotJoinStart + joinMap.ProgramUnregister, new Action<bool>
(b => SystemMonitor.ProgramCollection[programNumber].RegistrationState = eProgramRegistrationState.Unregister));
p.Value.ProgramUnregisteredFeedback.LinkInputSig(trilist.BooleanInput[programSlotJoinStart + joinMap.ProgramUnregister]);
programSlotJoinStart = programSlotJoinStart + joinMap.ProgramOffsetJoin;
}
}
}
public class SystemMonitorJoinMap : JoinMapBase
{
/// <summary>
/// Offset to indicate where the range of iterated program joins will start
/// </summary>
public uint ProgramStartJoin { get; set; }
/// <summary>
/// Offset between each program join set
/// </summary>
public uint ProgramOffsetJoin { get; set; }
//Digital
public uint ProgramStart { get; set; }
public uint ProgramStop { get; set; }
public uint ProgramRegister { get; set; }
public uint ProgramUnregister { get; set; }
//Analog
public uint TimeZone { get; set; }
//Serial
public uint TimeZoneName { get; set; }
public uint IOControllerVersion { get; set; }
public uint SnmpAppVersion { get; set; }
public uint BACnetAppVersion { get; set; }
public uint ControllerVersion { get; set; }
public uint ProgramName { get; set; }
public uint ProgramCompiledTime { get; set; }
public uint ProgramCrestronDatabaseVersion { get; set; }
public uint ProgramEnvironmentVersion { get; set; }
public uint AggregatedProgramInfo { get; set; }
public SystemMonitorJoinMap()
{
TimeZone = 1;
TimeZoneName = 1;
IOControllerVersion = 2;
SnmpAppVersion = 3;
BACnetAppVersion = 4;
ControllerVersion = 5;
ProgramStartJoin = 10;
ProgramOffsetJoin = 5;
// Offset in groups of 5 joins
ProgramStart = 1;
ProgramStop = 2;
ProgramRegister = 3;
ProgramUnregister = 4;
ProgramName = 1;
ProgramCompiledTime = 2;
ProgramCrestronDatabaseVersion = 3;
ProgramEnvironmentVersion = 4;
AggregatedProgramInfo = 5;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
TimeZone = TimeZone + joinOffset;
TimeZoneName = TimeZoneName + joinOffset;
IOControllerVersion = IOControllerVersion + joinOffset;
SnmpAppVersion = SnmpAppVersion + joinOffset;
BACnetAppVersion = BACnetAppVersion + joinOffset;
ControllerVersion = ControllerVersion + joinOffset;
// Sets the initial join value where the iterated program joins will begin
ProgramStartJoin = ProgramStartJoin + joinOffset;
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
namespace PepperDash.Essentials.Bridges
{
public static class TvOneApiExtensions
{
public static void LinkToApi(this TVOneCorio TvOne, BasicTriList trilist, uint joinStart, string joinMapKey)
{
var joinMap = JoinMapHelper.GetJoinMapForDevice(joinMapKey) as TvOneJoinMap;
if (joinMap == null)
joinMap = new TvOneJoinMap();
joinMap.OffsetJoinNumbers(joinStart);
Debug.Console(1, TvOne, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
TvOne.OnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline]);
trilist.SetUShortSigAction(joinMap.CallPreset, u => TvOne.CallPreset(u));
TvOne.PresetFeedback.LinkInputSig(trilist.UShortInput[joinMap.PresetFeedback]);
}
}
public class TvOneJoinMap : JoinMapBase
{
public uint CallPreset { get; set; }
public uint PresetFeedback { get; set; }
public uint IsOnline { get; set; }
public TvOneJoinMap()
{
// Digital
CallPreset = 1;
PresetFeedback = 1;
IsOnline = 1;
}
public override void OffsetJoinNumbers(uint joinStart)
{
var joinOffset = joinStart - 1;
IsOnline = IsOnline + joinOffset;
CallPreset = CallPreset + joinOffset;
PresetFeedback = PresetFeedback + joinOffset;
}
}
}

View File

@@ -1,188 +0,0 @@
using System;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials
{
/// <summary>
/// Loads the ConfigObject from the file
/// </summary>
public class ConfigReader
{
public static EssentialsConfig ConfigObject { get; private set; }
public static bool LoadConfig2()
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading unmerged system/template portal configuration file.");
try
{
var filePath = Global.FilePathPrefix + "configurationFile.json";
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to load config file: '{0}'", filePath);
if (!File.Exists(filePath))
{
Debug.Console(0, Debug.ErrorLogLevel.Error,
"ERROR: Configuration file not present. Please load file to {0} and reset program", filePath);
return false;
}
using (StreamReader fs = new StreamReader(filePath))
{
var doubleObj = JObject.Parse(fs.ReadToEnd());
ConfigObject = MergeConfigs(doubleObj).ToObject<EssentialsConfig>();
// Extract SystemUrl and TemplateUrl into final config output
if (doubleObj["system_url"] != null)
{
ConfigObject.SystemUrl = doubleObj["system_url"].Value<string>();
}
if (doubleObj["template_url"] != null)
{
ConfigObject.TemplateUrl= doubleObj["template_url"].Value<string>();
}
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Successfully Loaded Merged Config");
return true;
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "ERROR: Config load failed: \r{0}", e);
return false;
}
}
static JObject MergeConfigs(JObject doubleConfig)
{
var system = JObject.FromObject(doubleConfig["system"]);
var template = JObject.FromObject(doubleConfig["template"]);
var merged = new JObject();
// Put together top-level objects
// skip any objects that don't have template objects
if (system["info"] != null)
merged.Add("info", Merge(template["info"], system["info"]));
else
merged.Add("info", template["info"]);
merged.Add("devices", MergeArraysOnTopLevelProperty(template["devices"] as JArray,
system["devices"] as JArray, "uid"));
if (template["rooms"] != null)
{
if (system["rooms"] == null)
merged.Add("rooms", template["rooms"]);
else
merged.Add("rooms", MergeArraysOnTopLevelProperty(template["rooms"] as JArray,
system["rooms"] as JArray, "key"));
}
if (template["sourceLists"] != null)
{
if (system["sourceLists"] == null)
merged.Add("sourceLists", template["sourceLists"]);
else
merged.Add("sourceLists", Merge(template["sourceLists"], system["sourceLists"]));
}
// Template tie lines take precdence. Config tool doesn't do them at system
// level anyway...
if (template["tieLines"] != null)
merged.Add("tieLines", template["tieLines"]);
//else if (system["tieLines"] != null)
// merged.Add("tieLines", system["tieLines"]);
//else
// merged.Add("tieLines", new JArray());
Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged);
return merged;
}
/// <summary>
/// Merges the contents of a base and a delta array, matching the entries on a top-level property
/// given by propertyName. Returns a merge of them. Items in the delta array that do not have
/// a matched item in base array will not be merged.
/// </summary>
static JArray MergeArraysOnTopLevelProperty(JArray a1, JArray a2, string propertyName)
{
var result = new JArray();
if (a2 == null)
result = a1;
else if (a1 != null)
{
for (int i = 0; i < a1.Count(); i++)
{
var a1Dev = a1[i];
// Try to get a system device and if found, merge it onto template
var a2Match = a2.FirstOrDefault(t => t[propertyName].Equals(a1Dev[propertyName]));// t.Value<int>("uid") == tmplDev.Value<int>("uid"));
if (a2Match != null)
{
var mergedItem = Merge(a1Dev, a2Match);// Merge(JObject.FromObject(a1Dev), JObject.FromObject(a2Match));
result.Add(mergedItem);
}
else
result.Add(a1Dev);
}
}
return result;
}
/// <summary>
/// Helper for using with JTokens. Converts to JObject
/// </summary>
static JObject Merge(JToken t1, JToken t2)
{
return Merge(JObject.FromObject(t1), JObject.FromObject(t2));
}
/// <summary>
/// Merge b ONTO a
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
static JObject Merge(JObject o1, JObject o2)
{
foreach (var o2Prop in o2)
{
var o1Value = o1[o2Prop.Key];
if (o1Value == null)
o1.Add(o2Prop.Key, o2Prop.Value);
else
{
JToken replacement = null;
if (o2Prop.Value.HasValues && o1Value.HasValues) // Drill down
replacement = Merge(JObject.FromObject(o1Value), JObject.FromObject(o2Prop.Value));
else
replacement = o2Prop.Value;
o1[o2Prop.Key].Replace(replacement);
}
}
return o1;
}
/// <summary>
/// Returns the group for a given device key in config
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static string GetGroupForDeviceKey(string key)
{
var dev = ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
return dev == null ? null : dev.Group;
}
}
}

View File

@@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
/// <summary>
/// Loads the ConfigObject from the file
/// </summary>
public class EssentialsConfig : BasicConfig
{
[JsonProperty("system_url")]
public string SystemUrl { get; set; }
[JsonProperty("template_url")]
public string TemplateUrl { get; set; }
//public CotijaConfig Cotija { get; private set; }
[JsonProperty("systemUuid")]
public string SystemUuid
{
get
{
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*");
string uuid = result.Groups[1].Value;
return uuid;
}
}
[JsonProperty("templateUuid")]
public string TemplateUuid
{
get
{
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*");
string uuid = result.Groups[1].Value;
return uuid;
}
}
[JsonProperty("rooms")]
public List<EssentialsRoomConfig> Rooms { get; set; }
}
/// <summary>
///
/// </summary>
public class SystemTemplateConfigs
{
public EssentialsConfig System { get; set; }
public EssentialsConfig Template { get; set; }
}
}

View File

@@ -80,6 +80,16 @@ namespace PepperDash.Essentials
var dm = new DmMd8x8(ipId, Global.ControlSystem);
//dev = new DmChassisController(devKey, devName, dm);
}
else if (devType.Equals("dmmd16x16", StringComparison.OrdinalIgnoreCase))
{
var dm = new DmMd16x16(ipId, Global.ControlSystem);
//dev = new DmChassisController(devKey, devName, dm);
}
else if (devType.Equals("dmmd32x32", StringComparison.OrdinalIgnoreCase))
{
var dm = new DmMd32x32(ipId, Global.ControlSystem);
//dev = new DmChassisController(devKey, devName, dm);
}
}
catch (Exception e)
{

View File

@@ -1,359 +1,425 @@
using System;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.CrestronThread;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion;
using PepperDash.Essentials.Room.Cotija;
namespace PepperDash.Essentials
{
public class ControlSystem : CrestronControlSystem
{
HttpLogoServer LogoServer;
public ControlSystem()
: base()
{
Thread.MaxNumberOfUserThreads = 400;
Global.ControlSystem = this;
DeviceManager.Initialize(this);
}
/// <summary>
/// Git 'er goin'
/// </summary>
public override void InitializeSystem()
{
DeterminePlatform();
//CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
// ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
foreach (var tl in TieLineCollection.Default)
CrestronConsole.ConsoleCommandResponse(" {0}\r", tl);
},
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse
("Current running configuration. This is the merged system and template configuration");
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse("This system can be found at the following URLs:\r" +
"System URL: {0}\r" +
"Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
}, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
GoWithLoad();
}
/// <summary>
/// Determines if the program is running on a processor (appliance) or server (XiO Edge).
///
/// Sets Global.FilePathPrefix based on platform
/// </summary>
public void DeterminePlatform()
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform....");
string filePathPrefix;
var dirSeparator = Global.DirectorySeparator;
var version = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
var versionString = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
string directoryPrefix;
//directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory();
#warning ^ For use with beta Include4.dat for XiO Edge
directoryPrefix = "";
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server)
{
filePathPrefix = directoryPrefix + dirSeparator + "NVRAM"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", versionString);
}
else
{
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on XiO Edge Server", versionString);
}
Global.SetFilePathPrefix(filePathPrefix);
}
/// <summary>
/// Do it, yo
/// </summary>
public void GoWithLoad()
{
try
{
CrestronConsole.AddNewConsoleCommand(EnablePortalSync, "portalsync", "Loads Portal Sync",
ConsoleAccessLevelEnum.AccessOperator);
//PortalSync = new PepperDashPortalSyncClient();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials load from configuration");
var filesReady = SetupFilesystem();
if (filesReady)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Folder structure verified. Loading config...");
if (!ConfigReader.LoadConfig2())
return;
Load();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Essentials load complete\r" +
"-------------------------------------------------------------");
}
else
{
Debug.Console(0,
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"Essentials file structure setup completed.\r" +
"Please load config, sgd and ir files and\r" +
"restart program.\r" +
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"------------------------------------------------");
}
}
catch (Exception e)
{
Debug.Console(0, "FATAL INITIALIZE ERROR. System is in an inconsistent state:\r{0}", e);
}
}
/// <summary>
/// Verifies filesystem is set up. IR, SGD, and program1 folders
/// </summary>
bool SetupFilesystem()
{
Debug.Console(0, "Verifying and/or creating folder structure");
var configDir = Global.FilePathPrefix;
var configExists = Directory.Exists(configDir);
if (!configExists)
Directory.Create(configDir);
var irDir = Global.FilePathPrefix + "ir";
if (!Directory.Exists(irDir))
Directory.Create(irDir);
var sgdDir = Global.FilePathPrefix + "sgd";
if (!Directory.Exists(sgdDir))
Directory.Create(sgdDir);
return configExists;
}
public void EnablePortalSync(string s)
{
if (s.ToLower() == "enable")
{
CrestronConsole.ConsoleCommandResponse("Portal Sync features enabled");
}
}
public void TearDown()
{
Debug.Console(0, "Tearing down existing system");
DeviceManager.DeactivateAll();
TieLineCollection.Default.Clear();
foreach (var key in DeviceManager.GetDevices())
DeviceManager.RemoveDevice(key);
Debug.Console(0, "Tear down COMPLETE");
}
/// <summary>
///
/// </summary>
void Load()
{
LoadDevices();
LoadTieLines();
LoadRooms();
LoadLogoServer();
DeviceManager.ActivateAll();
}
/// <summary>
/// Reads all devices from config and adds them to DeviceManager
/// </summary>
public void LoadDevices()
{
foreach (var devConf in ConfigReader.ConfigObject.Devices)
{
try
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Creating device '{0}'", devConf.Key);
// Skip this to prevent unnecessary warnings
if (devConf.Key == "processor")
continue;
// Try local factory first
var newDev = DeviceFactory.GetDevice(devConf);
// Then associated library factories
if (newDev == null)
newDev = PepperDash.Essentials.Devices.Common.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.DM.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.Devices.Displays.DisplayDeviceFactory.GetDevice(devConf);
if (newDev != null)
DeviceManager.AddDevice(newDev);
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Cannot load unknown device type '{0}', key '{1}'.", devConf.Type, devConf.Key);
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Creating device {0}. Skipping device. \r{1}", devConf.Key, e);
}
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Devices Loaded.");
}
/// <summary>
/// Helper method to load tie lines. This should run after devices have loaded
/// </summary>
public void LoadTieLines()
{
// In the future, we can't necessarily just clear here because devices
// might be making their own internal sources/tie lines
var tlc = TieLineCollection.Default;
//tlc.Clear();
if (ConfigReader.ConfigObject.TieLines == null)
{
return;
}
foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
{
var newTL = tieLineConfig.GetTieLine();
if (newTL != null)
tlc.Add(newTL);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Tie Lines Loaded.");
}
/// <summary>
/// Reads all rooms from config and adds them to DeviceManager
/// </summary>
public void LoadRooms()
{
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Warning, "WARNING: Configuration contains no rooms");
return;
}
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
{
var room = roomConfig.GetRoomObject();
if (room != null)
{
if (room is EssentialsHuddleSpaceRoom)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge...");
// Cotija bridge
var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room as EssentialsHuddleSpaceRoom);
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
DeviceManager.AddDevice(bridge);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Cotija Bridge Added...");
}
else if (room is EssentialsHuddleVtc1Room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, 0xf1));
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsHuddleSpaceRoom, attempting to add to DeviceManager w/o Fusion");
DeviceManager.AddDevice(room);
}
}
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create room from config, key '{0}'", roomConfig.Key);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded.");
}
/// <summary>
/// Helps add the post activation steps that link bridges to main controller
/// </summary>
/// <param name="bridge"></param>
void AddBridgePostActivationHelper(CotijaBridgeBase bridge)
{
bridge.AddPostActivationAction(() =>
{
var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController;
if (parent == null)
{
Debug.Console(0, bridge, "ERROR: Cannot connect bridge. System controller not present");
}
Debug.Console(0, bridge, "Linking to parent controller");
bridge.AddParent(parent);
parent.AddBridge(bridge);
});
}
/// <summary>
/// Fires up a logo server if not already running
/// </summary>
void LoadLogoServer()
{
try
{
LogoServer = new HttpLogoServer(8080, Global.FilePathPrefix + "html" + Global.DirectorySeparator + "logo");
}
catch (Exception)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "NOTICE: Logo server cannot be started. Likely already running in another program");
}
}
}
}
using System;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.CrestronThread;
using Crestron.SimplSharpPro.Diagnostics;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Room.Cotija;
namespace PepperDash.Essentials
{
public class ControlSystem : CrestronControlSystem
{
HttpLogoServer LogoServer;
public ControlSystem()
: base()
{
Thread.MaxNumberOfUserThreads = 400;
Global.ControlSystem = this;
DeviceManager.Initialize(this);
}
/// <summary>
/// Git 'er goin'
/// </summary>
public override void InitializeSystem()
{
SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true;
DeterminePlatform();
//CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
// ConsoleAccessLevelEnum.AccessOperator);
// CrestronConsole.AddNewConsoleCommand(S => { ConfigWriter.WriteConfigFile(null); }, "writeconfig", "writes the current config to a file", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "CONSOLE MESSAGE: {0}", s);
}, "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
foreach (var tl in TieLineCollection.Default)
CrestronConsole.ConsoleCommandResponse(" {0}\r", tl);
},
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse
("Current running configuration. This is the merged system and template configuration");
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse("This system can be found at the following URLs:\r" +
"System URL: {0}\r" +
"Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
}, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
GoWithLoad();
}
/// <summary>
/// Determines if the program is running on a processor (appliance) or server (XiO Edge).
///
/// Sets Global.FilePathPrefix based on platform
/// </summary>
public void DeterminePlatform()
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform....");
string filePathPrefix;
var dirSeparator = Global.DirectorySeparator;
var version = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
var versionString = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
string directoryPrefix;
directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory();
//directoryPrefix = "";
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server)
{
filePathPrefix = directoryPrefix + dirSeparator + "NVRAM"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", versionString);
}
else
{
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on Virtual Control Server", versionString);
}
Global.SetFilePathPrefix(filePathPrefix);
}
/// <summary>
/// Do it, yo
/// </summary>
public void GoWithLoad()
{
try
{
CrestronConsole.AddNewConsoleCommand(EnablePortalSync, "portalsync", "Loads Portal Sync",
ConsoleAccessLevelEnum.AccessOperator);
//PortalSync = new PepperDashPortalSyncClient();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials load from configuration");
var filesReady = SetupFilesystem();
if (filesReady)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Folder structure verified. Loading config...");
if (!ConfigReader.LoadConfig2())
return;
Load();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Essentials load complete\r" +
"-------------------------------------------------------------");
}
else
{
Debug.Console(0,
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"Essentials file structure setup completed.\r" +
"Please load config, sgd and ir files and\r" +
"restart program.\r" +
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"------------------------------------------------");
}
}
catch (Exception e)
{
Debug.Console(0, "FATAL INITIALIZE ERROR. System is in an inconsistent state:\r{0}", e);
}
// Notify the
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
/// <summary>
/// Verifies filesystem is set up. IR, SGD, and program1 folders
/// </summary>
bool SetupFilesystem()
{
Debug.Console(0, "Verifying and/or creating folder structure");
var configDir = Global.FilePathPrefix;
var configExists = Directory.Exists(configDir);
if (!configExists)
Directory.Create(configDir);
var irDir = Global.FilePathPrefix + "ir";
if (!Directory.Exists(irDir))
Directory.Create(irDir);
var sgdDir = Global.FilePathPrefix + "sgd";
if (!Directory.Exists(sgdDir))
Directory.Create(sgdDir);
return configExists;
}
public void EnablePortalSync(string s)
{
if (s.ToLower() == "enable")
{
CrestronConsole.ConsoleCommandResponse("Portal Sync features enabled");
}
}
public void TearDown()
{
Debug.Console(0, "Tearing down existing system");
DeviceManager.DeactivateAll();
TieLineCollection.Default.Clear();
foreach (var key in DeviceManager.GetDevices())
DeviceManager.RemoveDevice(key);
Debug.Console(0, "Tear down COMPLETE");
}
/// <summary>
///
/// </summary>
void Load()
{
LoadDevices();
LoadTieLines();
LoadRooms();
LoadLogoServer();
DeviceManager.ActivateAll();
LinkSystemMonitorToAppServer();
}
void LinkSystemMonitorToAppServer()
{
var sysMon = DeviceManager.GetDeviceForKey("systemMonitor") as PepperDash.Essentials.Core.Monitoring.SystemMonitorController;
var appServer = DeviceManager.GetDeviceForKey("appServer") as CotijaSystemController;
if (sysMon != null && appServer != null)
{
var key = sysMon.Key + "-" + appServer.Key;
var messenger = new PepperDash.Essentials.AppServer.Messengers.SystemMonitorMessenger
(key, sysMon, "/device/systemMonitor");
messenger.RegisterWithAppServer(appServer);
DeviceManager.AddDevice(messenger);
}
}
/// <summary>
/// Reads all devices from config and adds them to DeviceManager
/// </summary>
public void LoadDevices()
{
# warning Missing PepperDash.Essentials.Core.Devices.CrestronProcessor("processor"));
// Build the processor wrapper class
// DeviceManager.AddDevice(new PepperDash.Essentials.Core.Devices.CrestronProcessor("processor"));
// Add global System Monitor device
DeviceManager.AddDevice(new PepperDash.Essentials.Core.Monitoring.SystemMonitorController("systemMonitor"));
foreach (var devConf in ConfigReader.ConfigObject.Devices)
{
try
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Creating device '{0}'", devConf.Key);
// Skip this to prevent unnecessary warnings
if (devConf.Key == "processor")
{
if (devConf.Type.ToLower() != Global.ControlSystem.ControllerPrompt.ToLower())
Debug.Console(0,
"WARNING: Config file defines processor type as '{0}' but actual processor is '{1}'! Some ports may not be available",
devConf.Type.ToUpper(), Global.ControlSystem.ControllerPrompt.ToUpper());
continue;
}
// Try local factories first
var newDev = DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = BridgeFactory.GetDevice(devConf);
// Then associated library factories
if (newDev == null)
newDev = PepperDash.Essentials.Core.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.Devices.Common.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.DM.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.Devices.Displays.DisplayDeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.BridgeFactory.GetDevice(devConf);
if (newDev != null)
DeviceManager.AddDevice(newDev);
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Cannot load unknown device type '{0}', key '{1}'.", devConf.Type, devConf.Key);
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Creating device {0}. Skipping device. \r{1}", devConf.Key, e);
}
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Devices Loaded.");
}
/// <summary>
/// Helper method to load tie lines. This should run after devices have loaded
/// </summary>
public void LoadTieLines()
{
// In the future, we can't necessarily just clear here because devices
// might be making their own internal sources/tie lines
var tlc = TieLineCollection.Default;
//tlc.Clear();
if (ConfigReader.ConfigObject.TieLines == null)
{
return;
}
foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
{
var newTL = tieLineConfig.GetTieLine();
if (newTL != null)
tlc.Add(newTL);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Tie Lines Loaded.");
}
/// <summary>
/// Reads all rooms from config and adds them to DeviceManager
/// </summary>
public void LoadRooms()
{
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Warning, "WARNING: Configuration contains no rooms");
return;
}
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
{
var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as EssentialsRoomBase;
if (room != null)
{
if (room is EssentialsHuddleSpaceRoom)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge...");
// Cotija bridge
var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room as EssentialsHuddleSpaceRoom);
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
DeviceManager.AddDevice(bridge);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Cotija Bridge Added...");
}
else if (room is EssentialsHuddleVtc1Room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, 0xf1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge...");
// Cotija bridge
var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room);
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
DeviceManager.AddDevice(bridge);
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion");
DeviceManager.AddDevice(room);
}
}
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create room from config, key '{0}'", roomConfig.Key);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded.");
}
/// <summary>
/// Helps add the post activation steps that link bridges to main controller
/// </summary>
/// <param name="bridge"></param>
void AddBridgePostActivationHelper(CotijaBridgeBase bridge)
{
bridge.AddPostActivationAction(() =>
{
var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController;
if (parent == null)
{
Debug.Console(0, bridge, "ERROR: Cannot connect app server room bridge. System controller not present");
return;
}
Debug.Console(0, bridge, "Linking to parent controller");
bridge.AddParent(parent);
parent.AddBridge(bridge);
});
}
/// <summary>
/// Fires up a logo server if not already running
/// </summary>
void LoadLogoServer()
{
try
{
LogoServer = new HttpLogoServer(8080, Global.DirectorySeparator + "html" + Global.DirectorySeparator + "logo");
}
catch (Exception)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "NOTICE: Logo server cannot be started. Likely already running in another program");
}
}
}
}

View File

@@ -1,367 +0,0 @@
using System;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.CrestronThread;
using PepperDash.Core;
using PepperDash.Core.PortalSync;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion;
using PepperDash.Essentials.Room.Cotija;
namespace PepperDash.Essentials
{
public class ControlSystem : CrestronControlSystem
{
PepperDashPortalSyncClient PortalSync;
HttpLogoServer LogoServer;
public ControlSystem()
: base()
{
Thread.MaxNumberOfUserThreads = 400;
Global.ControlSystem = this;
DeviceManager.Initialize(this);
}
/// <summary>
/// Git 'er goin'
/// </summary>
public override void InitializeSystem()
{
<<<<<<< HEAD
DeterminePlatform();
//CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
// ConsoleAccessLevelEnum.AccessOperator);
=======
CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
ConsoleAccessLevelEnum.AccessOperator);
>>>>>>> 600b9f11ff1bbc186f7c2a2945955731b3523b3c
CrestronConsole.AddNewConsoleCommand(s =>
{
foreach (var tl in TieLineCollection.Default)
CrestronConsole.ConsoleCommandResponse(" {0}\r", tl);
},
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse
("Current running configuration. This is the merged system and template configuration");
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse("This system can be found at the following URLs:\r" +
"System URL: {0}\r" +
"Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
}, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
//GoWithLoad();
}
/// <summary>
/// Determines if the program is running on a processor (appliance) or server (XiO Edge).
///
/// Sets Global.FilePathPrefix based on platform
/// </summary>
public void DeterminePlatform()
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform....");
string filePathPrefix;
var dirSeparator = Global.DirectorySeparator;
var version = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
var versionString = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
string directoryPrefix;
//directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory();
#warning ^ For use with beta Include4.dat for XiO Edge
directoryPrefix = "";
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server)
{
filePathPrefix = directoryPrefix + dirSeparator + "NVRAM"
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", versionString);
}
else
{
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on XiO Edge Server", versionString);
}
Global.SetFilePathPrefix(filePathPrefix);
}
/// <summary>
/// Do it, yo
/// </summary>
public void GoWithLoad()
{
try
{
CrestronConsole.AddNewConsoleCommand(EnablePortalSync, "portalsync", "Loads Portal Sync",
ConsoleAccessLevelEnum.AccessOperator);
//PortalSync = new PepperDashPortalSyncClient();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials load from configuration");
var filesReady = SetupFilesystem();
if (filesReady)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Folder structure verified. Loading config...");
if (!ConfigReader.LoadConfig2())
return;
Load();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Essentials load complete\r" +
"-------------------------------------------------------------");
}
else
{
Debug.Console(0,
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"Essentials file structure setup completed.\r" +
"Please load config, sgd and ir files and\r" +
"restart program.\r" +
"------------------------------------------------\r" +
"------------------------------------------------\r" +
"------------------------------------------------");
}
}
catch (Exception e)
{
Debug.Console(0, "FATAL INITIALIZE ERROR. System is in an inconsistent state:\r{0}", e);
}
}
/// <summary>
/// Verifies filesystem is set up. IR, SGD, and program1 folders
/// </summary>
bool SetupFilesystem()
{
Debug.Console(0, "Verifying and/or creating folder structure");
var configDir = Global.FilePathPrefix;
var configExists = Directory.Exists(configDir);
if (!configExists)
Directory.Create(configDir);
var irDir = Global.FilePathPrefix + "ir";
if (!Directory.Exists(irDir))
Directory.Create(irDir);
var sgdDir = Global.FilePathPrefix + "sgd";
if (!Directory.Exists(sgdDir))
Directory.Create(sgdDir);
return configExists;
}
public void EnablePortalSync(string s)
{
if (s.ToLower() == "enable")
{
CrestronConsole.ConsoleCommandResponse("Portal Sync features enabled");
PortalSync = new PepperDashPortalSyncClient();
}
}
public void TearDown()
{
Debug.Console(0, "Tearing down existing system");
DeviceManager.DeactivateAll();
TieLineCollection.Default.Clear();
foreach (var key in DeviceManager.GetDevices())
DeviceManager.RemoveDevice(key);
Debug.Console(0, "Tear down COMPLETE");
}
/// <summary>
///
/// </summary>
void Load()
{
LoadDevices();
LoadTieLines();
LoadRooms();
LoadLogoServer();
DeviceManager.ActivateAll();
}
/// <summary>
/// Reads all devices from config and adds them to DeviceManager
/// </summary>
public void LoadDevices()
{
foreach (var devConf in ConfigReader.ConfigObject.Devices)
{
try
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Creating device '{0}'", devConf.Key);
// Skip this to prevent unnecessary warnings
if (devConf.Key == "processor")
continue;
// Try local factory first
var newDev = DeviceFactory.GetDevice(devConf);
// Then associated library factories
if (newDev == null)
newDev = PepperDash.Essentials.Devices.Common.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.DM.DeviceFactory.GetDevice(devConf);
if (newDev == null)
newDev = PepperDash.Essentials.Devices.Displays.DisplayDeviceFactory.GetDevice(devConf);
if (newDev != null)
DeviceManager.AddDevice(newDev);
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Cannot load unknown device type '{0}', key '{1}'.", devConf.Type, devConf.Key);
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Creating device {0}. Skipping device. \r{1}", devConf.Key, e);
}
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Devices Loaded.");
}
/// <summary>
/// Helper method to load tie lines. This should run after devices have loaded
/// </summary>
public void LoadTieLines()
{
// In the future, we can't necessarily just clear here because devices
// might be making their own internal sources/tie lines
var tlc = TieLineCollection.Default;
//tlc.Clear();
if (ConfigReader.ConfigObject.TieLines == null)
{
return;
}
foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
{
var newTL = tieLineConfig.GetTieLine();
if (newTL != null)
tlc.Add(newTL);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Tie Lines Loaded.");
}
/// <summary>
/// Reads all rooms from config and adds them to DeviceManager
/// </summary>
public void LoadRooms()
{
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Warning, "WARNING: Configuration contains no rooms");
return;
}
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
{
var room = roomConfig.GetRoomObject();
if (room != null)
{
if (room is EssentialsHuddleSpaceRoom)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge...");
// Cotija bridge
var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room as EssentialsHuddleSpaceRoom);
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
DeviceManager.AddDevice(bridge);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Cotija Bridge Added...");
}
else if (room is EssentialsHuddleVtc1Room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, 0xf1));
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsHuddleSpaceRoom, attempting to add to DeviceManager w/o Fusion");
DeviceManager.AddDevice(room);
}
}
else
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create room from config, key '{0}'", roomConfig.Key);
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded.");
}
/// <summary>
/// Helps add the post activation steps that link bridges to main controller
/// </summary>
/// <param name="bridge"></param>
void AddBridgePostActivationHelper(CotijaBridgeBase bridge)
{
bridge.AddPostActivationAction(() =>
{
var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController;
if (parent == null)
{
Debug.Console(0, bridge, "ERROR: Cannot connect bridge. System controller not present");
}
Debug.Console(0, bridge, "Linking to parent controller");
bridge.AddParent(parent);
parent.AddBridge(bridge);
});
}
/// <summary>
/// Fires up a logo server if not already running
/// </summary>
void LoadLogoServer()
{
try
{
LogoServer = new HttpLogoServer(8080, Global.FilePathPrefix + "html" + Global.DirectorySeparator + "logo");
}
catch (Exception)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "NOTICE: Logo server cannot be started. Likely already running in another program");
}
}
}
}

View File

@@ -17,6 +17,7 @@ using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Devices.Common.Occupancy;
@@ -30,6 +31,10 @@ namespace PepperDash.Essentials.Fusion
//public event EventHandler<MeetingChangeEventArgs> MeetingEndWarning;
//public event EventHandler<MeetingChangeEventArgs> NextMeetingBeginWarning;
public event EventHandler<EventArgs> RoomInfoChange;
public FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge();
protected FusionRoom FusionRoom;
protected EssentialsRoomBase Room;
Dictionary<Device, BoolInputSig> SourceToFeedbackSigs =
@@ -334,6 +339,8 @@ namespace PepperDash.Essentials.Fusion
FusionRoom.ErrorMessage.InputSig.StringValue =
"3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;";
SetUpEthernetValues();
GetProcessorEthernetValues();
GetSystemInfo();
@@ -363,7 +370,7 @@ namespace PepperDash.Essentials.Fusion
systemReboot.OutputSig.SetSigFalseAction(() => CrestronConsole.SendControlSystemCommand("reboot", ref response));
}
protected void GetProcessorEthernetValues()
protected void SetUpEthernetValues()
{
Ip1 = FusionRoom.CreateOffsetStringSig(50, "Info - Processor - IP 1", eSigIoMask.InputSigOnly);
Ip2 = FusionRoom.CreateOffsetStringSig(51, "Info - Processor - IP 2", eSigIoMask.InputSigOnly);
@@ -376,8 +383,10 @@ namespace PepperDash.Essentials.Fusion
Mac2 = FusionRoom.CreateOffsetStringSig(58, "Info - Processor - MAC 2", eSigIoMask.InputSigOnly);
NetMask1 = FusionRoom.CreateOffsetStringSig(59, "Info - Processor - Net Mask 1", eSigIoMask.InputSigOnly);
NetMask2 = FusionRoom.CreateOffsetStringSig(60, "Info - Processor - Net Mask 2", eSigIoMask.InputSigOnly);
}
// Interface =0
protected void GetProcessorEthernetValues()
{
Ip1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
Gateway.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0);
Hostname.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
@@ -420,6 +429,16 @@ namespace PepperDash.Essentials.Fusion
}
protected void GetCustomProperties()
{
if (FusionRoom.IsOnline)
{
string fusionRoomCustomPropertiesRequest = @"<RequestRoomConfiguration><RequestID>RoomConfigurationRequest</RequestID><CustomProperties><Property></Property></CustomProperties></RequestRoomConfiguration>";
FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigQuery.StringValue = fusionRoomCustomPropertiesRequest;
}
}
void GetTouchpanelInfo()
{
// TODO Get IP and Project Name from TP
@@ -465,6 +484,7 @@ namespace PepperDash.Essentials.Fusion
FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = actionRequest;
GetCustomProperties();
// Request current Fusion Server Time
RequestLocalDateTime(null);
@@ -748,6 +768,82 @@ namespace PepperDash.Essentials.Fusion
Debug.Console(1, this, "Error parsing LocalDateTimeQueryResponse: {0}", e);
}
}
else if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigResponse)
{
// Room info response with custom properties
string roomConfigResponseArgs = args.Sig.StringValue.Replace("&", "and");
Debug.Console(2, this, "Fusion Response: \n {0}", roomConfigResponseArgs);
try
{
XmlDocument roomConfigResponse = new XmlDocument();
roomConfigResponse.LoadXml(roomConfigResponseArgs);
var requestRoomConfiguration = roomConfigResponse["RoomConfigurationResponse"];
if (requestRoomConfiguration != null)
{
RoomInformation roomInformation = new RoomInformation();
foreach (XmlElement e in roomConfigResponse.FirstChild.ChildNodes)
{
if (e.Name == "RoomInformation")
{
XmlReader roomInfo = new XmlReader(e.OuterXml);
roomInformation = CrestronXMLSerialization.DeSerializeObject<RoomInformation>(roomInfo);
}
else if (e.Name == "CustomFields")
{
foreach (XmlElement el in e)
{
FusionCustomProperty customProperty = new FusionCustomProperty();
if (el.Name == "CustomField")
{
customProperty.ID = el.Attributes["ID"].Value;
}
foreach (XmlElement elm in el)
{
if (elm.Name == "CustomFieldName")
{
customProperty.CustomFieldName = elm.InnerText;
}
if (elm.Name == "CustomFieldType")
{
customProperty.CustomFieldType = elm.InnerText;
}
if (elm.Name == "CustomFieldValue")
{
customProperty.CustomFieldValue = elm.InnerText;
}
}
roomInformation.FusionCustomProperties.Add(customProperty);
}
}
}
var handler = RoomInfoChange;
if (handler != null)
handler(this, new EventArgs());
CustomPropertiesBridge.EvaluateRoomInfo(Room.Key, roomInformation);
}
}
catch (Exception e)
{
Debug.Console(1, this, "Error parsing Custom Properties response: {0}", e);
}
//PrintRoomInfo();
//getRoomInfoBusy = false;
//_DynFusion.API.EISC.BooleanInput[Constants.GetRoomInfo].BoolValue = getRoomInfoBusy;
}
}
/// <summary>
@@ -1461,5 +1557,39 @@ namespace PepperDash.Essentials.Fusion
}
}
public class RoomInformation
{
public string ID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public string Description { get; set; }
public string TimeZone { get; set; }
public string WebcamURL { get; set; }
public string BacklogMsg { get; set; }
public string SubErrorMsg { get; set; }
public string EmailInfo { get; set; }
public List<FusionCustomProperty> FusionCustomProperties { get; set; }
public RoomInformation()
{
FusionCustomProperties = new List<FusionCustomProperty>();
}
}
public class FusionCustomProperty
{
public string ID { get; set; }
public string CustomFieldName { get; set; }
public string CustomFieldType { get; set; }
public string CustomFieldValue { get; set; }
public FusionCustomProperty()
{
}
public FusionCustomProperty(string id)
{
ID = id;
}
}
}

View File

@@ -13,6 +13,7 @@ using Crestron.SimplSharpPro.Fusion;
using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Devices.Common.Occupancy;
@@ -186,14 +187,7 @@ namespace PepperDash.Essentials.Fusion
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff"));
// NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig);
FusionRoom.ErrorMessage.InputSig.StringValue =
"3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;";
GetProcessorEthernetValues();
GetSystemInfo();
GetProcessorInfo();
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
}

View File

@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Room.Behaviours;
namespace PepperDash.Essentials.Fusion
{
/// <summary>
/// Handles mapping Fusion Custom Property values to system properties
/// </summary>
public class FusionCustomPropertiesBridge
{
/// <summary>
/// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed
/// </summary>
/// <param name="roomInfo"></param>
public void EvaluateRoomInfo(string roomKey, RoomInformation roomInfo)
{
try
{
var reconfigurableDevices = DeviceManager.AllDevices.Where(d => d is ReconfigurableDevice);
foreach (var device in reconfigurableDevices)
{
// Get the current device config so new values can be overwritten over existing
var deviceConfig = (device as ReconfigurableDevice).Config;
if (device is RoomOnToDefaultSourceWhenOccupied)
{
Debug.Console(1, "Mapping Room on via Occupancy values from Fusion");
var devProps = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(deviceConfig.Properties.ToString());
var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied"));
if (enableFeature != null)
devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue);
var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime"));
if (enableTime != null)
devProps.OccupancyStartTime = enableTime.CustomFieldValue;
var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime"));
if (disableTime != null)
devProps.OccupancyEndTime = disableTime.CustomFieldValue;
var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun"));
if (enableSunday != null)
devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue);
var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon"));
if (enableMonday != null)
devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue);
var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue"));
if (enableTuesday != null)
devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue);
var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed"));
if (enableWednesday != null)
devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue);
var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu"));
if (enableThursday != null)
devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue);
var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri"));
if (enableFriday != null)
devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue);
var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat"));
if (enableSaturday != null)
devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue);
deviceConfig.Properties = JToken.FromObject(devProps);
}
else if (device is EssentialsRoomBase)
{
// Set the room name
if (!string.IsNullOrEmpty(roomInfo.Name))
{
Debug.Console(1, "Current Room Name: {0}. New Room Name: {1}", deviceConfig.Name, roomInfo.Name);
// Set the name in config
deviceConfig.Name = roomInfo.Name;
Debug.Console(1, "Room Name Successfully Changed.");
}
// Set the help message
var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage"));
if (helpMessage != null)
{
//Debug.Console(1, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value<string>(ToString()), helpMessage.CustomFieldValue);
deviceConfig.Properties["helpMessage"] = (string)helpMessage.CustomFieldValue;
}
}
// Set the config on the device
(device as ReconfigurableDevice).SetConfig(deviceConfig);
}
}
catch (Exception e)
{
Debug.Console(1, "FusionCustomPropetiesBridge: Error mapping properties: {0}", e);
}
}
}
}

View File

@@ -1,92 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials
{
public class DeviceFactory
{
public static IKeyed GetDevice(DeviceConfig dc)
{
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var typeName = dc.Type.ToLower();
if (typeName == "amplifier")
{
return new Amplifier(dc.Key, dc.Name);
}
else if (dc.Group.ToLower() == "touchpanel") // typeName.StartsWith("tsw"))
{
return UiDeviceFactory.GetUiDevice(dc);
}
else if (typeName == "mockdisplay")
{
return new MockDisplay(key, name);
}
else if (typeName == "generic")
{
return new Device(key, name);
}
// MOVE into something else???
else if (typeName == "basicirdisplay")
{
var ir = IRPortHelper.GetIrPort(properties);
if (ir != null)
return new BasicIrDisplay(key, name, ir.Port, ir.FileName);
}
else if (typeName == "commmock")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<ConsoleCommMockDevicePropertiesConfig>(
properties.ToString());
return new ConsoleCommMockDevice(key, name, props, comm);
}
else if (typeName == "appserver")
{
var props = JsonConvert.DeserializeObject<CotijaConfig>(properties.ToString());
return new CotijaSystemController(key, name, props);
}
else if (typeName == "mobilecontrolbridge-ddvc01")
{
var comm = CommFactory.GetControlPropertiesConfig(dc);
var bridge = new PepperDash.Essentials.Room.Cotija.CotijaDdvc01RoomBridge(key, name, comm.IpIdInt);
bridge.AddPreActivationAction(() =>
{
var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController;
if (parent == null)
{
Debug.Console(0, bridge, "ERROR: Cannot connect bridge. System controller not present");
}
Debug.Console(0, bridge, "Linking to parent controller");
bridge.AddParent(parent);
parent.AddBridge(bridge);
});
return bridge;
}
return null;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials
{
public class DeviceFactory
{
public static IKeyed GetDevice(DeviceConfig dc)
{
var key = dc.Key;
var name = dc.Name;
var type = dc.Type;
var properties = dc.Properties;
var typeName = dc.Type.ToLower();
if (typeName == "amplifier")
{
return new Amplifier(dc.Key, dc.Name);
}
else if (dc.Group.ToLower() == "touchpanel") // typeName.StartsWith("tsw"))
{
return UiDeviceFactory.GetUiDevice(dc);
}
else if (typeName == "mockdisplay")
{
return new MockDisplay(key, name);
}
else if (typeName == "generic")
{
return new Device(key, name);
}
// MOVE into something else???
else if (typeName == "basicirdisplay")
{
var ir = IRPortHelper.GetIrPort(properties);
if (ir != null)
return new BasicIrDisplay(key, name, ir.Port, ir.FileName);
}
else if (typeName == "commmock")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<ConsoleCommMockDevicePropertiesConfig>(
properties.ToString());
return new ConsoleCommMockDevice(key, name, props, comm);
}
else if (typeName == "appserver")
{
var props = JsonConvert.DeserializeObject<CotijaConfig>(properties.ToString());
return new CotijaSystemController(key, name, props);
}
else if (typeName == "mobilecontrolbridge-ddvc01")
{
var comm = CommFactory.GetControlPropertiesConfig(dc);
var bridge = new PepperDash.Essentials.Room.Cotija.CotijaDdvc01RoomBridge(key, name, comm.IpIdInt);
bridge.AddPreActivationAction(() =>
{
var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController;
if (parent == null)
{
Debug.Console(0, bridge, "ERROR: Cannot connect bridge. System controller not present");
}
Debug.Console(0, bridge, "Linking to parent controller");
bridge.AddParent(parent);
parent.AddBridge(bridge);
});
return bridge;
}
else if (typeName == "roomonwhenoccupancydetectedfeature")
{
return new Room.Behaviours.RoomOnToDefaultSourceWhenOccupied(dc);
}
return null;
}
}
}

View File

@@ -44,17 +44,17 @@ namespace PepperDash.Essentials
// AV Driver
Debug.Console(0, panelController, "Adding huddle space AV driver");
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props);
avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom;
avDriver.DefaultRoomKey = props.DefaultRoomKey;
mainDriver.AvDriver = avDriver;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom;
// Environment Driver
if (avDriver.CurrentRoom.Config.Environment != null && avDriver.CurrentRoom.Config.Environment.DeviceKeys.Count > 0)
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, panelController, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, props);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.Config.Environment);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);
@@ -113,17 +113,17 @@ namespace PepperDash.Essentials
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(panelController.Panel, avDriver,
(room as EssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
avDriver.SetVideoCodecDriver(codecDriver);
avDriver.CurrentRoom = room as EssentialsHuddleVtc1Room;
avDriver.DefaultRoomKey = props.DefaultRoomKey;
mainDriver.AvDriver = avDriver;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as EssentialsHuddleVtc1Room;
// Environment Driver
if (avDriver.CurrentRoom.Config.Environment != null && avDriver.CurrentRoom.Config.Environment.DeviceKeys.Count > 0)
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, panelController, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, props);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.Config.Environment);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
mainDriver.HeaderDriver.SetupHeaderButtons(avDriver, avDriver.CurrentRoom);

View File

@@ -1,227 +1,254 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1BED5BA9-88C4-4365-9362-6F4B128071D3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PepperDash.Essentials</RootNamespace>
<AssemblyName>PepperDashEssentials</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92230};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="Crestron.SimplSharpPro.DeviceSupport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DeviceSupport.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.DM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DM.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.EthernetCommunications, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.EthernetCommunications.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.Fusion, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Fusion.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.Remotes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Remotes.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.3.27452, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\essentials-framework\references\PepperDash_Core.dll</HintPath>
</Reference>
<Reference Include="PepperDash_Essentials_DM, Version=1.0.0.19343, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\essentials-framework\Essentials DM\Essentials_DM\bin\PepperDash_Essentials_DM.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</Reference>
<Reference Include="SimplSharpPro, Version=1.5.2.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="Audio\EssentialsVolumeLevelConfig.cs" />
<Compile Include="Configuration ORIGINAL\Builders\TPConfig.cs" />
<Compile Include="Configuration ORIGINAL\Configuration.cs" />
<Compile Include="Configuration ORIGINAL\ConfigurationHelpers.cs" />
<Compile Include="Configuration ORIGINAL\ConfigTieLine.cs" />
<Compile Include="Configuration ORIGINAL\Factories\CommFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\RemoteFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\DeviceMonitorFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\DmFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\TouchpanelFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\PcFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\REMOVE DiscPlayerFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\MAYBE SetTopBoxFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\DisplayFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\FactoryHelper.cs" />
<Compile Include="Config\ConfigReader.cs" />
<Compile Include="Config\EssentialsConfig.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Devices\Amplifier.cs" />
<Compile Include="Devices\DiscPlayer\OppoExtendedBdp.cs" />
<Compile Include="Devices\NUMERIC AppleTV.cs" />
<Compile Include="ControlSystem.cs" />
<Compile Include="Factory\UiDeviceFactory.cs" />
<Compile Include="OTHER\Fusion\EssentialsHuddleVtc1FusionController.cs" />
<Compile Include="OTHER\Fusion\FusionEventHandlers.cs" />
<Compile Include="OTHER\Fusion\FusionProcessorQueries.cs" />
<Compile Include="OTHER\Fusion\FusionRviDataClasses.cs" />
<Compile Include="REMOVE EssentialsApp.cs" />
<Compile Include="OTHER\Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
<Compile Include="HttpApiHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Room\Config\DDVC01RoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsPresentationPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
<Compile Include="Room\Cotija\CotijaConfig.cs" />
<Compile Include="Room\Cotija\CotijaDdvc01DeviceBridge.cs" />
<Compile Include="Room\Cotija\Interfaces.cs" />
<Compile Include="Room\Cotija\RoomBridges\CotijaBridgeBase.cs" />
<Compile Include="Room\Cotija\RoomBridges\CotijaDdvc01RoomBridge.cs" />
<Compile Include="Room\Cotija\RoomBridges\CotijaEssentialsHuddleSpaceRoomBridge.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\IChannelExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\IColorExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\IDPadExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\IDvrExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\INumericExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\IPowerExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\ISetTopBoxControlsExtensions.cs" />
<Compile Include="Room\Cotija\DeviceTypeInterfaces\ITransportExtensions.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsPresentationRoom.cs" />
<Compile Include="Room\Types\EssentialsRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\DevicePageControllerBase.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLaptop.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLargeDvd.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLargeSetTopBoxGeneric.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\LargeTouchpanelControllerBase.cs" />
<Compile Include="FOR REFERENCE UI\Panels\SmartGraphicsTouchpanelControllerBase.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsHeaderDriver.cs" />
<Compile Include="UIDrivers\SigInterlock.cs" />
<Compile Include="UIDrivers\EssentialsHuddleVTC\EssentialsHuddlePresentationUiDriver.cs" />
<Compile Include="UIDrivers\EssentialsHuddle\EssentialsHuddleTechPageDriver.cs" />
<Compile Include="UI\HttpLogoServer.cs" />
<Compile Include="UI\SmartObjectHeaderButtonList.cs" />
<Compile Include="UI\SubpageReferenceListCallStagingItem.cs" />
<Compile Include="UIDrivers\VC\EssentialsVideoCodecUiDriver.cs" />
<Compile Include="UIDrivers\JoinedSigInterlock.cs" />
<Compile Include="UIDrivers\EssentialsHuddleVTC\EssentialsHuddleVtc1PanelAvFunctionsDriver.cs" />
<Compile Include="UIDrivers\VolumeAndSourceChangeArgs.cs" />
<Compile Include="UI\JoinConstants\UISmartObjectJoin.cs" />
<Compile Include="UI\JoinConstants\UIStringlJoin.cs" />
<Compile Include="UI\JoinConstants\UIUshortJoin.cs" />
<Compile Include="UIDrivers\DualDisplayRouting.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsPresentationPanelAvFunctionsDriver.cs" />
<Compile Include="UIDrivers\Page Drivers\SingleSubpageModalDriver.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsPanelMainInterfaceDriver.cs" />
<Compile Include="UIDrivers\enums and base.cs" />
<Compile Include="UIDrivers\EssentialsHuddle\EssentialsHuddlePanelAvFunctionsDriver.cs" />
<Compile Include="UIDrivers\Page Drivers\SingleSubpageModalAndBackDriver.cs" />
<Compile Include="UIDrivers\SmartObjectRoomsList.cs" />
<Compile Include="UI\JoinConstants\UIBoolJoin.cs" />
<Compile Include="Room\Cotija\CotijaSystemController.cs" />
<Compile Include="UI\DualDisplaySourceSRLController.cs" />
<Compile Include="UI\SubpageReferenceListActivityItem.cs" />
<Compile Include="UI\CrestronTouchpanelPropertiesConfig.cs" />
<Compile Include="FOR REFERENCE UI\Panels\REMOVE UiCue.cs" />
<Compile Include="FOR REFERENCE UI\SRL\SourceListSubpageReferenceList.cs" />
<Compile Include="Room\Types\EssentialsHuddleSpaceRoom.cs" />
<Compile Include="UI\EssentialsTouchpanelController.cs" />
<Compile Include="UI\SubpageReferenceListSourceItem.cs" />
<None Include="app.config" />
<None Include="Properties\ControlSystem.cfg" />
<EmbeddedResource Include="SGD\PepperDash Essentials iPad.sgd" />
<EmbeddedResource Include="SGD\PepperDash Essentials TSW-560.sgd" />
<EmbeddedResource Include="SGD\PepperDash Essentials TSW-760.sgd" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\essentials-framework\Essentials Core\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj">
<Project>{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}</Project>
<Name>PepperDash_Essentials_Core</Name>
</ProjectReference>
<ProjectReference Include="..\essentials-framework\Essentials Devices Common\Essentials Devices Common\Essentials Devices Common.csproj">
<Project>{892B761C-E479-44CE-BD74-243E9214AF13}</Project>
<Name>Essentials Devices Common</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>rem S# Pro preparation will execute after these operations</PostBuildEvent>
</PropertyGroup>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1BED5BA9-88C4-4365-9362-6F4B128071D3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PepperDash.Essentials</RootNamespace>
<AssemblyName>PepperDashEssentials</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92230};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="Crestron.SimplSharpPro.DeviceSupport, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DeviceSupport.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.DM, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.DM.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.EthernetCommunications, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.EthernetCommunications.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.Fusion, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Fusion.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.Remotes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Remotes.dll</HintPath>
</Reference>
<Reference Include="Crestron.SimplSharpPro.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.3.27452, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\essentials-framework\references\PepperDash_Core.dll</HintPath>
</Reference>
<Reference Include="PepperDash_Essentials_DM, Version=1.0.0.19343, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\essentials-framework\Essentials DM\Essentials_DM\bin\PepperDash_Essentials_DM.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</Reference>
<Reference Include="SimplSharpPro, Version=1.5.2.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe</HintPath>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpTimerEventInterface, Version=1.0.6197.20052, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpTimerEventInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="AppServer\Messengers\AtcDdvc01Messenger.cs" />
<Compile Include="AppServer\Messengers\AudioCodecBaseMessenger.cs" />
<Compile Include="AppServer\Messengers\MessengerBase.cs" />
<Compile Include="AppServer\Messengers\SystemMonitorMessenger.cs" />
<Compile Include="AppServer\Messengers\VideoCodecBaseMessenger.cs" />
<Compile Include="Audio\EssentialsVolumeLevelConfig.cs" />
<Compile Include="Bridges\BridgeBase.cs" />
<Compile Include="Bridges\BridgeFactory.cs" />
<Compile Include="Bridges\CameraControllerBridge.cs" />
<Compile Include="Bridges\QscDspBridge.cs" />
<Compile Include="Bridges\TvOneBridge.cs" />
<Compile Include="Bridges\DisplayControllerBridge.cs" />
<Compile Include="Bridges\DigitalLoggerBridge.cs" />
<Compile Include="Bridges\DmChassisControllerBridge.cs" />
<Compile Include="Bridges\DmTxControllerBridge.cs" />
<Compile Include="Bridges\GenericLightingBridge.cs" />
<Compile Include="Bridges\GenericRelayDeviceBridge.cs" />
<Compile Include="Bridges\IBasicCommunicationBridge.cs" />
<Compile Include="Bridges\DmRmcControllerBridge.cs" />
<Compile Include="Bridges\IDigitalInputBridge.cs" />
<Compile Include="Bridges\JoinMapBase.cs" />
<Compile Include="Bridges\SystemMonitorBridge.cs" />
<Compile Include="Configuration ORIGINAL\Builders\TPConfig.cs" />
<Compile Include="Configuration ORIGINAL\Configuration.cs" />
<Compile Include="Configuration ORIGINAL\ConfigurationHelpers.cs" />
<Compile Include="Configuration ORIGINAL\ConfigTieLine.cs" />
<Compile Include="Configuration ORIGINAL\Factories\CommFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\RemoteFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\DeviceMonitorFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\DmFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\TouchpanelFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\PcFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\REMOVE DiscPlayerFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\MAYBE SetTopBoxFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\DisplayFactory.cs" />
<Compile Include="Configuration ORIGINAL\Factories\FactoryHelper.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Devices\Amplifier.cs" />
<Compile Include="Devices\DiscPlayer\OppoExtendedBdp.cs" />
<Compile Include="Devices\NUMERIC AppleTV.cs" />
<Compile Include="ControlSystem.cs" />
<Compile Include="Factory\UiDeviceFactory.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\EssentialsHuddleVtc1FusionController.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionCustomPropertiesBridge.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionEventHandlers.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionProcessorQueries.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionRviDataClasses.cs" />
<Compile Include="REMOVE EssentialsApp.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
<Compile Include="HttpApiHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
<Compile Include="Room\Config\DDVC01RoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsPresentationPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
<Compile Include="AppServer\CotijaConfig.cs" />
<Compile Include="AppServer\CotijaDdvc01DeviceBridge.cs" />
<Compile Include="AppServer\Interfaces.cs" />
<Compile Include="AppServer\RoomBridges\CotijaBridgeBase.cs" />
<Compile Include="AppServer\RoomBridges\CotijaDdvc01RoomBridge.cs" />
<Compile Include="AppServer\RoomBridges\CotijaEssentialsHuddleSpaceRoomBridge.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\IChannelExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\IColorExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\IDPadExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\IDvrExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\INumericExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\IPowerExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\ISetTopBoxControlsExtensions.cs" />
<Compile Include="AppServer\DeviceTypeInterfaces\ITransportExtensions.cs" />
<Compile Include="AppServer\RoomBridges\SourceDeviceMapDictionary.cs" />
<Compile Include="AppServer\Volumes.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsPresentationRoom.cs" />
<Compile Include="Room\Types\EssentialsRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\DevicePageControllerBase.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLaptop.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLargeDvd.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLargeSetTopBoxGeneric.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\LargeTouchpanelControllerBase.cs" />
<Compile Include="FOR REFERENCE UI\Panels\SmartGraphicsTouchpanelControllerBase.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsHeaderDriver.cs" />
<Compile Include="UIDrivers\JoinedSigInterlock.cs" />
<Compile Include="UIDrivers\SigInterlock.cs" />
<Compile Include="UIDrivers\EssentialsHuddleVTC\EssentialsHuddlePresentationUiDriver.cs" />
<Compile Include="UIDrivers\EssentialsHuddle\EssentialsHuddleTechPageDriver.cs" />
<Compile Include="UI\HttpLogoServer.cs" />
<Compile Include="UI\SmartObjectHeaderButtonList.cs" />
<Compile Include="UI\SubpageReferenceListCallStagingItem.cs" />
<Compile Include="UIDrivers\VC\EssentialsVideoCodecUiDriver.cs" />
<Compile Include="UIDrivers\EssentialsHuddleVTC\EssentialsHuddleVtc1PanelAvFunctionsDriver.cs" />
<Compile Include="UIDrivers\SourceChangeArgs.cs" />
<Compile Include="UI\JoinConstants\UISmartObjectJoin.cs" />
<Compile Include="UI\JoinConstants\UIStringlJoin.cs" />
<Compile Include="UI\JoinConstants\UIUshortJoin.cs" />
<Compile Include="UIDrivers\DualDisplayRouting.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsPresentationPanelAvFunctionsDriver.cs" />
<Compile Include="UIDrivers\Page Drivers\SingleSubpageModalDriver.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsPanelMainInterfaceDriver.cs" />
<Compile Include="UIDrivers\enums and base.cs" />
<Compile Include="UIDrivers\EssentialsHuddle\EssentialsHuddlePanelAvFunctionsDriver.cs" />
<Compile Include="UIDrivers\Page Drivers\SingleSubpageModalAndBackDriver.cs" />
<Compile Include="UIDrivers\SmartObjectRoomsList.cs" />
<Compile Include="UI\JoinConstants\UIBoolJoin.cs" />
<Compile Include="AppServer\CotijaSystemController.cs" />
<Compile Include="UI\DualDisplaySourceSRLController.cs" />
<Compile Include="UI\SubpageReferenceListActivityItem.cs" />
<Compile Include="UI\CrestronTouchpanelPropertiesConfig.cs" />
<Compile Include="FOR REFERENCE UI\Panels\REMOVE UiCue.cs" />
<Compile Include="FOR REFERENCE UI\SRL\SourceListSubpageReferenceList.cs" />
<Compile Include="Room\Types\EssentialsHuddleSpaceRoom.cs" />
<Compile Include="UI\EssentialsTouchpanelController.cs" />
<Compile Include="UI\SubpageReferenceListSourceItem.cs" />
<None Include="app.config" />
<None Include="Properties\ControlSystem.cfg" />
<EmbeddedResource Include="SGD\PepperDash Essentials iPad.sgd" />
<EmbeddedResource Include="SGD\PepperDash Essentials TSW-560.sgd" />
<EmbeddedResource Include="SGD\PepperDash Essentials TSW-760.sgd" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\essentials-framework\Essentials Core\PepperDashEssentialsBase\PepperDash_Essentials_Core.csproj">
<Project>{A49AD6C8-FC0A-4CC0-9089-DFB4CF92D2B5}</Project>
<Name>PepperDash_Essentials_Core</Name>
</ProjectReference>
<ProjectReference Include="..\essentials-framework\Essentials Devices Common\Essentials Devices Common\Essentials Devices Common.csproj">
<Project>{892B761C-E479-44CE-BD74-243E9214AF13}</Project>
<Name>Essentials Devices Common</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>rem S# Pro preparation will execute after these operations</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -3,6 +3,6 @@
[assembly: AssemblyTitle("PepperDashEssentials")]
[assembly: AssemblyCompany("PepperDash Technology Corp")]
[assembly: AssemblyProduct("PepperDashEssentials")]
[assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2017")]
[assembly: AssemblyVersion("1.2.0.*")]
[assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2018")]
[assembly: AssemblyVersion("1.3.1.*")]

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ControlSystem>
<Name>Test RMC3</Name>
<Address>auto 192.168.1.40</Address>
<ProgramSlot>Program01</ProgramSlot>
<Storage>Internal Flash</Storage>
<?xml version="1.0" encoding="utf-8"?>
<ControlSystem>
<Name>192.168.10.1</Name>
<Address>auto 192.168.10.1</Address>
<ProgramSlot>Program01</ProgramSlot>
<Storage>Internal Flash</Storage>
</ControlSystem>

View File

@@ -0,0 +1,526 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Occupancy;
namespace PepperDash.Essentials.Room.Behaviours
{
/// <summary>
/// A device that when linked to a room can power the room on when enabled during scheduled hours.
/// </summary>
public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice
{
RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig;
public bool FeatureEnabled { get; private set; }
public DateTime FeatureEnabledTime { get; private set; }
ScheduledEvent FeatureEnableEvent;
const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied";
public DateTime FeatureDisabledTime { get; private set; }
ScheduledEvent FeatureDisableEvent;
const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied";
ScheduledEventGroup FeatureEventGroup;
public EssentialsRoomBase Room { get; private set; }
private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom;
public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) :
base (config)
{
PropertiesConfig = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(config.Properties.ToString());
FeatureEventGroup = new ScheduledEventGroup(this.Key);
FeatureEventGroup.RetrieveAllEvents();
// Add to the global class for tracking
Scheduler.AddEventGroup(FeatureEventGroup);
AddPostActivationAction(() =>
{
// Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to
if (Room != null)
Room.RoomOccupancyIsSet += new EventHandler<EventArgs>(RoomOccupancyIsSet);
else
Debug.Console(1, this, "Room has no RoomOccupancy object set");
var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion";
FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Fusion.EssentialsHuddleSpaceFusionSystemControllerBase;
if (FusionRoom == null)
Debug.Console(1, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey);
});
}
public override bool CustomActivate()
{
SetUpDevice();
return base.CustomActivate();
}
/// <summary>
/// Sets up device based on config values
/// </summary>
void SetUpDevice()
{
Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as EssentialsRoomBase;
if (Room != null)
{
try
{
FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime);
if (FeatureEnabledTime != null)
{
Debug.Console(1, this, "Enabled Time: {0}", FeatureEnabledTime.ToString());
}
else
Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime);
}
catch (Exception e)
{
Debug.Console(1, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e);
}
try
{
FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime);
if (FeatureDisabledTime != null)
{
Debug.Console(1, this, "Disabled Time: {0}", FeatureDisabledTime.ToString());
}
else
Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime);
}
catch (Exception e)
{
Debug.Console(1, this, "Unable to parse a DateTime config value \n Error: {1}", e);
}
if (!PropertiesConfig.EnableRoomOnWhenOccupied)
FeatureEventGroup.ClearAllEvents();
else
{
AddEnableEventToGroup();
AddDisableEventToGroup();
FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack);
FeatureEventGroup.EnableAllEvents();
}
FeatureEnabled = CheckIfFeatureShouldBeEnabled();
}
else
Debug.Console(1, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey);
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(config.Properties.ToString());
if(newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateDeviceConfig(config);
SetUpDevice();
}
/// <summary>
/// Subscribe to feedback from RoomIsOccupiedFeedback on Room
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void RoomOccupancyIsSet(object sender, EventArgs e)
{
if (Room.RoomOccupancy != null)
{
Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler<FeedbackEventArgs>(RoomIsOccupiedFeedback_OutputChange);
Debug.Console(1, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key);
}
}
void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type)
{
if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration)
{
if (SchEvent.Name == FeatureEnableEventName)
{
if (PropertiesConfig.EnableRoomOnWhenOccupied)
FeatureEnabled = true;
Debug.Console(1, this, "*****Feature Enabled by event.*****");
}
else if (SchEvent.Name == FeatureDisableEventName)
{
FeatureEnabled = false;
Debug.Console(1, this, "*****Feature Disabled by event.*****");
}
}
}
/// <summary>
/// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time
/// </summary>
/// <returns></returns>
bool CheckIfFeatureShouldBeEnabled()
{
bool enabled = false;
if(PropertiesConfig.EnableRoomOnWhenOccupied)
{
Debug.Console(1, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime);
if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0)
{
if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence()))
{
enabled = true;
}
}
}
if(enabled)
Debug.Console(1, this, "*****Feature Enabled*****");
else
Debug.Console(1, this, "*****Feature Disabled*****");
return enabled;
}
/// <summary>
/// Respond to Occupancy status event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
Debug.Console(1, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue);
if(e.BoolValue)
{
// Occupancy detected
if (FeatureEnabled)
{
// Check room power state first
if (!Room.OnFeedback.BoolValue)
{
Debug.Console(1, this, "Powering Room on to default source");
Room.RunDefaultPresentRoute();
}
}
}
}
void CreateEvent(ScheduledEvent schEvent, string name)
{
Debug.Console(1, this, "Adding Event: '{0}'", name);
// Create the event
if (schEvent == null)
schEvent = new ScheduledEvent(name, FeatureEventGroup);
// Set up its initial properties
if(!schEvent.Acknowledgeable)
schEvent.Acknowledgeable = true;
if(!schEvent.Persistent)
schEvent.Persistent = true;
schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday);
// Set config driven properties
if (schEvent.Name == FeatureEnableEventName)
{
schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature";
var eventRecurrennce = CalculateDaysOfWeekRecurrence();
var eventTime = new DateTime();
// Check to make sure the date for this event is in the future
if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0)
eventTime = FeatureEnabledTime.AddDays(1);
else
eventTime = FeatureEnabledTime;
Debug.Console(1, this, "eventTime (before recurrence check): {0}", eventTime);
// Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event
// start date on a day of the week that doesn't match teh recurrence values
while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce))
{
eventTime = eventTime.AddDays(1);
Debug.Console(1, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime);
}
schEvent.DateAndTime.SetAbsoluteEventTime(eventTime);
Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString());
CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime);
schEvent.Recurrence.Weekly(eventRecurrennce);
}
else if (schEvent.Name == FeatureDisableEventName)
{
schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature";
// Check to make sure the date for this event is in the future
if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0)
schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1));
else
schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime);
Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString());
CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime);
schEvent.Recurrence.Daily();
}
}
void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2)
{
Debug.Console(1, this, "time1.Hour = {0}", time1.Hour);
Debug.Console(1, this, "time2.Hour = {0}", time2.Hour);
Debug.Console(1, this, "time1.Minute = {0}", time1.Minute);
Debug.Console(1, this, "time2.Minute = {0}", time2.Minute);
// Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute
var ackHours = time2.Hour - time1.Hour;
if(ackHours < 0)
ackHours = ackHours + 24;
var ackMinutes = time2.Minute - time1.Minute;
Debug.Console(1, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes);
var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1;
var ackExpHour = ackTotalMinutes / 60;
var ackExpMinutes = ackTotalMinutes % 60;
Debug.Console(1, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes);
schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours);
schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes);
}
/// <summary>
/// Checks existing event to see if it matches the execution time
/// </summary>
/// <param name="existingEvent"></param>
/// <returns></returns>
bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime)
{
bool isMatch = true;
// Check to see if hour and minute match
if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute)
return false;
return isMatch;
}
/// <summary>
/// Checks existing event to see if it matches the recurrence days
/// </summary>
/// <param name="existingEvent"></param>
/// <param name="eWeekdays"></param>
/// <returns></returns>
bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays)
{
bool isMatch = true;
// Check to see if recurrence matches
if (eWeekdays != existingEvent.Recurrence.RecurrenceDays)
return false;
return isMatch;
}
/// <summary>
/// Adds the Enable event to the local event group and sets its properties based on config
/// </summary>
void AddEnableEventToGroup()
{
if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName))
{
CreateEvent(FeatureEnableEvent, FeatureEnableEventName);
}
else
{
// Check if existing event has same time and recurrence as config values
FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName];
Debug.Console(1, this, "Enable event already found in group");
// Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event
if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence()))
{
Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name);
FeatureEventGroup.DeleteEvent(FeatureEnableEvent);
FeatureEnableEvent = null;
CreateEvent(FeatureEnableEvent, FeatureEnableEventName);
}
}
}
/// <summary>
/// Adds the Enable event to the local event group and sets its properties based on config
/// </summary>
void AddDisableEventToGroup()
{
if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName))
{
CreateEvent(FeatureDisableEvent, FeatureDisableEventName);
}
else
{
FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName];
Debug.Console(1, this, "Disable event already found in group");
// Check config times against DateAndTime of existing event. If different, delete existing event and create new event
if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime))
{
Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name);
FeatureEventGroup.DeleteEvent(FeatureDisableEvent);
FeatureDisableEvent = null;
CreateEvent(FeatureDisableEvent, FeatureDisableEventName);
}
}
}
/// <summary>
/// Calculates the correct bitfield enum value for the event recurrence based on the config values
/// </summary>
/// <returns></returns>
ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence()
{
ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays();
if (PropertiesConfig.EnableSunday)
value = value | ScheduledEventCommon.eWeekDays.Sunday;
if (PropertiesConfig.EnableMonday)
value = value | ScheduledEventCommon.eWeekDays.Monday;
if (PropertiesConfig.EnableTuesday)
value = value | ScheduledEventCommon.eWeekDays.Tuesday;
if (PropertiesConfig.EnableWednesday)
value = value | ScheduledEventCommon.eWeekDays.Wednesday;
if (PropertiesConfig.EnableThursday)
value = value | ScheduledEventCommon.eWeekDays.Thursday;
if (PropertiesConfig.EnableFriday)
value = value | ScheduledEventCommon.eWeekDays.Friday;
if (PropertiesConfig.EnableSaturday)
value = value | ScheduledEventCommon.eWeekDays.Saturday;
return value;
}
/// <summary>
/// Callback for event that enables feature. Enables feature if config property is true
/// </summary>
/// <param name="SchEvent"></param>
/// <param name="type"></param>
void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type)
{
if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration)
{
if(PropertiesConfig.EnableRoomOnWhenOccupied)
FeatureEnabled = true;
Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled.");
}
}
/// <summary>
/// Callback for event that enables feature. Disables feature
/// </summary>
/// <param name="SchEvent"></param>
/// <param name="type"></param>
void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type)
{
if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration)
{
FeatureEnabled = false;
Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled.");
}
}
}
public class RoomOnToDefaultSourceWhenOccupiedConfig
{
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
[JsonProperty("enableRoomOnWhenOccupied")]
public bool EnableRoomOnWhenOccupied { get; set; }
[JsonProperty("occupancyStartTime")]
public string OccupancyStartTime { get; set; }
[JsonProperty("occupancyEndTime")]
public string OccupancyEndTime { get; set; }
[JsonProperty("enableSunday")]
public bool EnableSunday { get; set; }
[JsonProperty("enableMonday")]
public bool EnableMonday { get; set; }
[JsonProperty("enableTuesday")]
public bool EnableTuesday { get; set; }
[JsonProperty("enableWednesday")]
public bool EnableWednesday { get; set; }
[JsonProperty("enableThursday")]
public bool EnableThursday { get; set; }
[JsonProperty("enableFriday")]
public bool EnableFriday { get; set; }
[JsonProperty("enableSaturday")]
public bool EnableSaturday { get; set; }
}
}

View File

@@ -20,5 +20,7 @@ namespace PepperDash.Essentials.Room.Config
public string DefaultSourceItem { get; set; }
[JsonProperty("videoCodecKey")]
public string VideoCodecKey { get; set; }
[JsonProperty("audioCodecKey")]
public string AudioCodecKey { get; set; }
}
}

View File

@@ -1,334 +1,284 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Room.Config
{
public class EssentialsRoomConfig : DeviceConfig
{
/// <summary>
/// Returns a room object from this config data
/// </summary>
/// <returns></returns>
public Device GetRoomObject()
{
var typeName = Type.ToLower();
if (typeName == "huddle")
{
var props = JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>
(this.Properties.ToString());
var disp = DeviceManager.GetDeviceForKey(props.DefaultDisplayKey) as IRoutingSinkWithSwitching;
var audio = DeviceManager.GetDeviceForKey(props.DefaultAudioKey) as IRoutingSinkNoSwitching;
var huddle = new EssentialsHuddleSpaceRoom(Key, Name, disp, audio, props);
if (props.Occupancy != null)
huddle.SetRoomOccupancy(DeviceManager.GetDeviceForKey(props.Occupancy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, props.Occupancy.TimoutMinutes);
huddle.LogoUrl = props.Logo.GetUrl();
huddle.SourceListKey = props.SourceListKey;
huddle.DefaultSourceItem = props.DefaultSourceItem;
huddle.DefaultVolume = (ushort)(props.Volumes.Master.Level * 65535 / 100);
return huddle;
}
else if (typeName == "presentation")
{
var props = JsonConvert.DeserializeObject<EssentialsPresentationRoomPropertiesConfig>
(this.Properties.ToString());
var displaysDict = new Dictionary<uint, IRoutingSinkNoSwitching>();
uint i = 1;
foreach (var dispKey in props.DisplayKeys) // read in the ordered displays list
{
var disp = DeviceManager.GetDeviceForKey(dispKey) as IRoutingSinkWithSwitching;
displaysDict.Add(i++, disp);
}
// Get the master volume control
IBasicVolumeWithFeedback masterVolumeControlDev = props.Volumes.Master.GetDevice();
var presRoom = new EssentialsPresentationRoom(Key, Name, displaysDict, masterVolumeControlDev, props);
return presRoom;
}
else if (typeName == "huddlevtc1")
{
var props = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>
(this.Properties.ToString());
var disp = DeviceManager.GetDeviceForKey(props.DefaultDisplayKey) as IRoutingSinkWithSwitching;
var codec = DeviceManager.GetDeviceForKey(props.VideoCodecKey) as
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
var rm = new EssentialsHuddleVtc1Room(Key, Name, disp, codec, codec, props);
// Add Occupancy object from config
if (props.Occupancy != null)
rm.SetRoomOccupancy(DeviceManager.GetDeviceForKey(props.Occupancy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, props.Occupancy.TimoutMinutes);
rm.LogoUrl = props.Logo.GetUrl();
rm.SourceListKey = props.SourceListKey;
rm.DefaultSourceItem = props.DefaultSourceItem;
rm.DefaultVolume = (ushort)(props.Volumes.Master.Level * 65535 / 100);
rm.MicrophonePrivacy = GetMicrophonePrivacy(props, rm); // Get Microphone Privacy object, if any
rm.Emergency = GetEmergency(props, rm); // Get emergency object, if any
return rm;
}
else if (typeName == "ddvc01Bridge")
{
return new Device(Key, Name); // placeholder device that does nothing.
}
return null;
}
/// <summary>
/// Gets and operating, standalone emergegncy object that can be plugged into a room.
/// Returns null if there is no emergency defined
/// </summary>
EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room)
{
// This emergency
var emergency = props.Emergency;
if (emergency != null)
{
//switch on emergency type here. Right now only contact and shutdown
var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room);
DeviceManager.AddDevice(e);
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="props"></param>
/// <param name="room"></param>
/// <returns></returns>
PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController GetMicrophonePrivacy(
EssentialsRoomPropertiesConfig props, EssentialsHuddleVtc1Room room)
{
var microphonePrivacy = props.MicrophonePrivacy;
if (microphonePrivacy == null)
{
Debug.Console(0, "ERROR: Cannot create microphone privacy with null properties");
return null;
}
// Get the MicrophonePrivacy device from the device manager
var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController);
// Set this room as the IPrivacy device
if (mP == null)
{
Debug.Console(0, "ERROR: Selected device {0} is not MicrophonePrivacyController", props.MicrophonePrivacy.DeviceKey);
return null;
}
mP.SetPrivacyDevice(room);
var behaviour = props.MicrophonePrivacy.Behaviour.ToLower();
if (behaviour == null)
{
Debug.Console(0, "WARNING: No behaviour defined for MicrophonePrivacyController");
return null;
}
if (behaviour == "trackroomstate")
{
// Tie LED enable to room power state
room.OnFeedback.OutputChange += (o, a) =>
{
if (room.OnFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
mP.EnableLeds = room.OnFeedback.BoolValue;
}
else if (behaviour == "trackcallstate")
{
// Tie LED enable to room power state
room.InCallFeedback.OutputChange += (o, a) =>
{
if (room.InCallFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
mP.EnableLeds = room.InCallFeedback.BoolValue;
}
return mP;
}
}
/// <summary>
///
/// </summary>
public class EssentialsRoomPropertiesConfig
{
[JsonProperty("addresses")]
public EssentialsRoomAddressPropertiesConfig Addresses { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("emergency")]
public EssentialsRoomEmergencyConfig Emergency { get; set; }
[JsonProperty("help")]
public EssentialsHelpPropertiesConfig Help { get; set; }
[JsonProperty("helpMessage")]
public string HelpMessage { get; set; }
[JsonProperty("environment")]
public EssentialsEnvironmentPropertiesConfig Environment { get; set; }
[JsonProperty("logo")]
public EssentialsLogoPropertiesConfig Logo { get; set; }
[JsonProperty("microphonePrivacy")]
public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; }
[JsonProperty("occupancy")]
public EssentialsRoomOccSensorConfig Occupancy { get; set; }
[JsonProperty("oneButtonMeeting")]
public EssentialsOneButtonMeetingPropertiesConfig OneButtonMeeting { get; set; }
[JsonProperty("shutdownVacancySeconds")]
public int ShutdownVacancySeconds { get; set; }
[JsonProperty("shutdownPromptSeconds")]
public int ShutdownPromptSeconds { get; set; }
[JsonProperty("tech")]
public EssentialsRoomTechConfig Tech { get; set; }
[JsonProperty("volumes")]
public EssentialsRoomVolumesConfig Volumes { get; set; }
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
}
public class EssentialsEnvironmentPropertiesConfig
{
public bool Enabled { get; set; }
[JsonProperty("deviceKeys")]
public List<string> DeviceKeys { get; set; }
public EssentialsEnvironmentPropertiesConfig()
{
DeviceKeys = new List<string>();
}
}
public class EssentialsRoomMicrophonePrivacyConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("behaviour")]
public string Behaviour { get; set; }
}
/// <summary>
/// Properties for the help text box
/// </summary>
public class EssentialsHelpPropertiesConfig
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("showCallButton")]
public bool ShowCallButton { get; set; }
/// <summary>
/// Defaults to "Call Help Desk"
/// </summary>
[JsonProperty("callButtonText")]
public string CallButtonText { get; set; }
public EssentialsHelpPropertiesConfig()
{
CallButtonText = "Call Help Desk";
}
}
/// <summary>
///
/// </summary>
public class EssentialsOneButtonMeetingPropertiesConfig
{
[JsonProperty("enable")]
public bool Enable { get; set; }
}
public class EssentialsRoomAddressPropertiesConfig
{
[JsonProperty("phoneNumber")]
public string PhoneNumber { get; set; }
[JsonProperty("sipAddress")]
public string SipAddress { get; set; }
}
/// <summary>
/// Properties for the room's logo on panels
/// </summary>
public class EssentialsLogoPropertiesConfig
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
/// <summary>
/// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo
/// </summary>
public string GetUrl()
{
if (Type == "url")
return Url;
if (Type == "system")
return string.Format("http://{0}:8080/logo.png",
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0));
return null;
}
}
/// <summary>
/// Represents occupancy sensor(s) setup for a room
/// </summary>
public class EssentialsRoomOccSensorConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("timoutMinutes")]
public int TimoutMinutes { get; set; }
}
public class EssentialsRoomTechConfig
{
[JsonProperty("password")]
public string Password { get; set; }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Room.Config
{
public class EssentialsRoomConfigHelper
{
/// <summary>
/// Returns a room object from this config data
/// </summary>
/// <returns></returns>
public static Device GetRoomObject(DeviceConfig roomConfig)
{
var typeName = roomConfig.Type.ToLower();
if (typeName == "huddle")
{
var huddle = new EssentialsHuddleSpaceRoom(roomConfig);
return huddle;
}
else if (typeName == "huddlevtc1")
{
var rm = new EssentialsHuddleVtc1Room(roomConfig);
return rm;
}
else if (typeName == "ddvc01Bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
return null;
}
/// <summary>
/// Gets and operating, standalone emergegncy object that can be plugged into a room.
/// Returns null if there is no emergency defined
/// </summary>
public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room)
{
// This emergency
var emergency = props.Emergency;
if (emergency != null)
{
//switch on emergency type here. Right now only contact and shutdown
var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room);
DeviceManager.AddDevice(e);
}
return null;
}
/// <summary>
///
/// </summary>
/// <param name="props"></param>
/// <param name="room"></param>
/// <returns></returns>
public static PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController GetMicrophonePrivacy(
EssentialsRoomPropertiesConfig props, EssentialsHuddleVtc1Room room)
{
var microphonePrivacy = props.MicrophonePrivacy;
if (microphonePrivacy == null)
{
Debug.Console(0, "ERROR: Cannot create microphone privacy with null properties");
return null;
}
// Get the MicrophonePrivacy device from the device manager
var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController);
// Set this room as the IPrivacy device
if (mP == null)
{
Debug.Console(0, "ERROR: Selected device {0} is not MicrophonePrivacyController", props.MicrophonePrivacy.DeviceKey);
return null;
}
mP.SetPrivacyDevice(room);
var behaviour = props.MicrophonePrivacy.Behaviour.ToLower();
if (behaviour == null)
{
Debug.Console(0, "WARNING: No behaviour defined for MicrophonePrivacyController");
return null;
}
if (behaviour == "trackroomstate")
{
// Tie LED enable to room power state
room.OnFeedback.OutputChange += (o, a) =>
{
if (room.OnFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
mP.EnableLeds = room.OnFeedback.BoolValue;
}
else if (behaviour == "trackcallstate")
{
// Tie LED enable to room power state
room.InCallFeedback.OutputChange += (o, a) =>
{
if (room.InCallFeedback.BoolValue)
mP.EnableLeds = true;
else
mP.EnableLeds = false;
};
mP.EnableLeds = room.InCallFeedback.BoolValue;
}
return mP;
}
}
/// <summary>
///
/// </summary>
public class EssentialsRoomPropertiesConfig
{
[JsonProperty("addresses")]
public EssentialsRoomAddressPropertiesConfig Addresses { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("emergency")]
public EssentialsRoomEmergencyConfig Emergency { get; set; }
[JsonProperty("help")]
public EssentialsHelpPropertiesConfig Help { get; set; }
[JsonProperty("helpMessage")]
public string HelpMessage { get; set; }
[JsonProperty("environment")]
public EssentialsEnvironmentPropertiesConfig Environment { get; set; }
[JsonProperty("logo")]
public EssentialsLogoPropertiesConfig Logo { get; set; }
[JsonProperty("microphonePrivacy")]
public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; }
[JsonProperty("occupancy")]
public EssentialsRoomOccSensorConfig Occupancy { get; set; }
[JsonProperty("oneButtonMeeting")]
public EssentialsOneButtonMeetingPropertiesConfig OneButtonMeeting { get; set; }
[JsonProperty("shutdownVacancySeconds")]
public int ShutdownVacancySeconds { get; set; }
[JsonProperty("shutdownPromptSeconds")]
public int ShutdownPromptSeconds { get; set; }
[JsonProperty("tech")]
public EssentialsRoomTechConfig Tech { get; set; }
[JsonProperty("volumes")]
public EssentialsRoomVolumesConfig Volumes { get; set; }
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
}
public class EssentialsEnvironmentPropertiesConfig
{
public bool Enabled { get; set; }
[JsonProperty("deviceKeys")]
public List<string> DeviceKeys { get; set; }
public EssentialsEnvironmentPropertiesConfig()
{
DeviceKeys = new List<string>();
}
}
public class EssentialsRoomMicrophonePrivacyConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("behaviour")]
public string Behaviour { get; set; }
}
/// <summary>
/// Properties for the help text box
/// </summary>
public class EssentialsHelpPropertiesConfig
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("showCallButton")]
public bool ShowCallButton { get; set; }
/// <summary>
/// Defaults to "Call Help Desk"
/// </summary>
[JsonProperty("callButtonText")]
public string CallButtonText { get; set; }
public EssentialsHelpPropertiesConfig()
{
CallButtonText = "Call Help Desk";
}
}
/// <summary>
///
/// </summary>
public class EssentialsOneButtonMeetingPropertiesConfig
{
[JsonProperty("enable")]
public bool Enable { get; set; }
}
public class EssentialsRoomAddressPropertiesConfig
{
[JsonProperty("phoneNumber")]
public string PhoneNumber { get; set; }
[JsonProperty("sipAddress")]
public string SipAddress { get; set; }
}
/// <summary>
/// Properties for the room's logo on panels
/// </summary>
public class EssentialsLogoPropertiesConfig
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
/// <summary>
/// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo
/// </summary>
public string GetUrl()
{
if (Type == "url")
return Url;
if (Type == "system")
return string.Format("http://{0}:8080/logo.png",
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0));
return null;
}
}
/// <summary>
/// Represents occupancy sensor(s) setup for a room
/// </summary>
public class EssentialsRoomOccSensorConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("timeoutMinutes")]
public int TimeoutMinutes { get; set; }
}
public class EssentialsRoomTechConfig
{
[JsonProperty("password")]
public string Password { get; set; }
}
}

View File

@@ -1,694 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro.CrestronThread;
using Crestron.SimplSharp.CrestronWebSocketClient;
using Crestron.SimplSharpPro;
using Crestron.SimplSharp.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Cotija;
namespace PepperDash.Essentials
{
public class CotijaSystemController : Device
{
WebSocketClient WSClient;
/// <summary>
/// Prevents post operations from stomping on each other and getting lost
/// </summary>
CEvent PostLockEvent = new CEvent(true, true);
CEvent RegisterLockEvent = new CEvent(true, true);
public CotijaConfig Config { get; private set; }
Dictionary<string, Object> ActionDictionary = new Dictionary<string, Object>(StringComparer.InvariantCultureIgnoreCase);
Dictionary<string, CTimer> PushedActions = new Dictionary<string, CTimer>();
CTimer ServerHeartbeatCheckTimer;
long ServerHeartbeatInterval = 20000;
CTimer ServerReconnectTimer;
long ServerReconnectInterval = 5000;
string SystemUuid;
List<CotijaBridgeBase> RoomBridges = new List<CotijaBridgeBase>();
long ButtonHeartbeatInterval = 1000;
/// <summary>
/// Used for tracking HTTP debugging
/// </summary>
bool HttpDebugEnabled;
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
/// <param name="config"></param>
public CotijaSystemController(string key, string name, CotijaConfig config) : base(key, name)
{
Config = config;
Debug.Console(0, this, "Mobile UI controller initializing for server:{0}", config.ServerUrl);
CrestronConsole.AddNewConsoleCommand(AuthorizeSystem,
"mobileauth", "Authorizes system to talk to cotija server", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => ShowInfo(),
"mobileinfo", "Shows information for current mobile control session", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s => {
s = s.Trim();
if(!string.IsNullOrEmpty(s))
{
HttpDebugEnabled = (s.Trim() != "0");
}
CrestronConsole.ConsoleCommandResponse("HTTP Debug {0}", HttpDebugEnabled ? "Enabled" : "Disabled");
},
"mobilehttpdebug", "1 enables more verbose HTTP response debugging", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(TestHttpRequest,
"mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator);
}
/// <summary>
/// Adds an action to the dictionary
/// </summary>
/// <param name="key">The path of the API command</param>
/// <param name="action">The action to be triggered by the commmand</param>
public void AddAction(string key, object action)
{
if (!ActionDictionary.ContainsKey(key))
{
ActionDictionary.Add(key, action);
}
else
{
Debug.Console(1, this, "Cannot add action with key '{0}' because key already exists in ActionDictionary.", key);
}
}
/// <summary>
/// Removes an action from the dictionary
/// </summary>
/// <param name="key"></param>
public void RemoveAction(string key)
{
if (ActionDictionary.ContainsKey(key))
ActionDictionary.Remove(key);
}
/// <summary>
///
/// </summary>
/// <param name="bridge"></param>
public void AddBridge(CotijaBridgeBase bridge)
{
RoomBridges.Add(bridge);
var b = bridge as IDelayedConfiguration;
if (b != null)
{
Debug.Console(0, this, "Adding room bridge with delayed configuration");
b.ConfigurationIsReady += new EventHandler<EventArgs>(bridge_ConfigurationIsReady);
}
else
{
Debug.Console(0, this, "Adding room bridge and sending configuration");
RegisterSystemToServer();
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void bridge_ConfigurationIsReady(object sender, EventArgs e)
{
Debug.Console(1, this, "Bridge ready. Registering");
// send the configuration object to the server
RegisterSystemToServer();
}
/// <summary>
///
/// </summary>
/// <param name="o"></param>
void ReconnectToServerTimerCallback(object o)
{
RegisterSystemToServer();
}
/// <summary>
/// Verifies system connection with servers
/// </summary>
/// <param name="command"></param>
void AuthorizeSystem(string code)
{
if (string.IsNullOrEmpty(code))
{
CrestronConsole.ConsoleCommandResponse("Please enter a user code to authorize a system");
return;
}
var req = new HttpClientRequest();
string url = string.Format("http://{0}/api/system/grantcode/{1}/{2}", Config.ServerUrl, code, SystemUuid);
Debug.Console(0, this, "Authorizing to: {0}", url);
if (string.IsNullOrEmpty(Config.ServerUrl))
{
CrestronConsole.ConsoleCommandResponse("Config URL address is not set. Check portal configuration");
return;
}
try
{
req.Url.Parse(url);
new HttpClient().DispatchAsync(req, (r, e) =>
{
CheckHttpDebug(r, e);
if (e == HTTP_CALLBACK_ERROR.COMPLETED)
{
if (r.Code == 200)
{
Debug.Console(0, "System authorized, sending config.");
RegisterSystemToServer();
}
else if (r.Code == 404)
{
if (r.ContentString.Contains("codeNotFound"))
{
Debug.Console(0, "Authorization failed, code not found for system UUID {0}", SystemUuid);
}
else if (r.ContentString.Contains("uuidNotFound"))
{
Debug.Console(0, "Authorization failed, uuid {0} not found. Check Essentials configuration is correct",
SystemUuid);
}
}
}
else
Debug.Console(0, this, "Error {0} in authorizing system", e);
});
}
catch (Exception e)
{
Debug.Console(0, this, "Error in authorizing: {0}", e);
}
}
/// <summary>
/// Dumps info in response to console command.
/// </summary>
void ShowInfo()
{
var url = Config != null ? Config.ServerUrl : "No config";
string name;
string code;
if (RoomBridges != null && RoomBridges.Count > 0)
{
name = RoomBridges[0].RoomName;
code = RoomBridges[0].UserCode;
}
else
{
name = "No config";
code = "Not available";
}
var conn = WSClient == null ? "No client" : (WSClient.Connected ? "Yes" : "No");
CrestronConsole.ConsoleCommandResponse(@"Mobile Control Information:
Server address: {0}
System Name: {1}
System UUID: {2}
System User code: {3}
Connected?: {4}", url, name, SystemUuid,
code, conn);
}
/// <summary>
/// Registers the room with the server
/// </summary>
/// <param name="url">URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port"</param>
void RegisterSystemToServer()
{
var ready = RegisterLockEvent.Wait(20000);
if (!ready)
{
Debug.Console(1, this, "RegisterSystemToServer failed to enter after 20 seconds. Ignoring");
return;
}
RegisterLockEvent.Reset();
try
{
var confObject = ConfigReader.ConfigObject;
confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name;
var version = Assembly.GetExecutingAssembly().GetName().Version;
confObject.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
confObject.Info.RuntimeInfo.OsVersion = Crestron.SimplSharp.CrestronEnvironment.OSVersion.Firmware;
string postBody = JsonConvert.SerializeObject(confObject);
SystemUuid = confObject.SystemUuid;
if (string.IsNullOrEmpty(postBody))
{
Debug.Console(1, this, "ERROR: Config body is empty. Cannot register with server.");
}
else
{
var regClient = new HttpClient();
regClient.Verbose = true;
regClient.KeepAlive = true;
string url = string.Format("http://{0}/api/system/join/{1}", Config.ServerUrl, SystemUuid);
Debug.Console(1, this, "Joining server at {0}", url);
HttpClientRequest request = new HttpClientRequest();
request.Url.Parse(url);
request.RequestType = RequestType.Post;
request.Header.SetHeaderValue("Content-Type", "application/json");
request.ContentString = postBody;
var err = regClient.DispatchAsync(request, RegistrationConnectionCallback);
}
}
catch (Exception e)
{
Debug.Console(0, this, "ERROR: Initilizing Room: {0}", e);
RegisterLockEvent.Set();
StartReconnectTimer();
}
}
/// <summary>
/// Sends a message to the server from a room
/// </summary>
/// <param name="room">room from which the message originates</param>
/// <param name="o">object to be serialized and sent in post body</param>
public void SendMessageToServer(JObject o)
{
if (WSClient != null && WSClient.Connected)
{
string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
Debug.Console(1, this, "Message TX: {0}", message);
var messageBytes = System.Text.Encoding.UTF8.GetBytes(message);
WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME);
//WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME);
}
<<<<<<< HEAD
=======
>>>>>>> feature/ecs-684
}
/// <summary>
/// Disconnects the SSE Client and stops the heartbeat timer
/// </summary>
/// <param name="command"></param>
void DisconnectStreamClient(string command)
{
//if(SseClient != null)
// SseClient.Disconnect();
if (WSClient != null && WSClient.Connected)
WSClient.Disconnect();
if (ServerHeartbeatCheckTimer != null)
{
ServerHeartbeatCheckTimer.Stop();
ServerHeartbeatCheckTimer = null;
}
}
/// <summary>
/// The callback that fires when we get a response from our registration attempt
/// </summary>
/// <param name="resp"></param>
/// <param name="err"></param>
void RegistrationConnectionCallback(HttpClientResponse resp, HTTP_CALLBACK_ERROR err)
{
CheckHttpDebug(resp, err);
Debug.Console(1, this, "RegistrationConnectionCallback: {0}", err);
try
{
if (resp != null && resp.Code == 200)
{
if(ServerReconnectTimer != null)
{
ServerReconnectTimer.Stop();
ServerReconnectTimer = null;
}
// Success here!
ConnectStreamClient();
}
else
{
if (resp != null)
Debug.Console(1, this, "Response from server: {0}\n{1}", resp.Code, err);
else
{
Debug.Console(1, this, "Null response received from server.");
}
StartReconnectTimer();
}
}
catch (Exception e)
{
Debug.Console(1, this, "Error Initializing Stream Client: {0}", e);
StartReconnectTimer();
}
RegisterLockEvent.Set();
}
/// <summary>
/// Executes when we don't get a heartbeat message in time. Triggers reconnect.
/// </summary>
/// <param name="o">For CTimer callback. Not used</param>
void HeartbeatExpiredTimerCallback(object o)
{
Debug.Console(1, this, "Heartbeat Timer Expired.");
if (ServerHeartbeatCheckTimer != null)
{
ServerHeartbeatCheckTimer.Stop();
ServerHeartbeatCheckTimer = null;
}
StartReconnectTimer();
}
/// <summary>
///
/// </summary>
/// <param name="dueTime"></param>
/// <param name="repeatTime"></param>
void StartReconnectTimer()
{
// Start the reconnect timer
if (ServerReconnectTimer == null)
{
ServerReconnectTimer = new CTimer(ReconnectToServerTimerCallback, null, ServerReconnectInterval, ServerReconnectInterval);
Debug.Console(1, this, "Reconnect Timer Started.");
}
ServerReconnectTimer.Reset(ServerReconnectInterval, ServerReconnectInterval);
}
/// <summary>
///
/// </summary>
/// <param name="dueTime"></param>
/// <param name="repeatTime"></param>
void ResetOrStartHearbeatTimer()
{
if (ServerHeartbeatCheckTimer == null)
{
ServerHeartbeatCheckTimer = new CTimer(HeartbeatExpiredTimerCallback, null, ServerHeartbeatInterval, ServerHeartbeatInterval);
Debug.Console(1, this, "Heartbeat Timer Started.");
}
ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval);
}
/// <summary>
/// Connects the SSE Client
/// </summary>
/// <param name="o"></param>
void ConnectStreamClient()
{
Debug.Console(0, this, "Initializing Stream client to server.");
if (WSClient == null)
{
WSClient = new WebSocketClient();
}
WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid);
WSClient.Connect();
Debug.Console(0, this, "Websocket connected");
WSClient.ReceiveCallBack = WebsocketReceiveCallback;
//WSClient.SendCallBack = WebsocketSendCallback;
WSClient.ReceiveAsync();
}
/// <summary>
/// Resets reconnect timer and updates usercode
/// </summary>
/// <param name="content"></param>
void HandleHeartBeat(JToken content)
{
var code = content["userCode"];
if(code != null)
{
foreach (var b in RoomBridges)
{
b.SetUserCode(code.Value<string>());
}
}
ResetOrStartHearbeatTimer();
}
/// <summary>
/// Outputs debug info when enabled
/// </summary>
/// <param name="req"></param>
/// <param name="r"></param>
/// <param name="e"></param>
void CheckHttpDebug(HttpClientResponse r, HTTP_CALLBACK_ERROR e)
{
if (HttpDebugEnabled)
{
Debug.Console(0, this, "------ Begin HTTP Debug ---------------------------------------");
Debug.Console(0, this, "HTTP Response URL: {0}", r.ResponseUrl.ToString());
Debug.Console(0, this, "HTTP Response 'error' {0}", e);
Debug.Console(0, this, "HTTP Response code: {0}", r.Code);
Debug.Console(0, this, "HTTP Response content: \r{0}", r.ContentString);
Debug.Console(0, this, "------ End HTTP Debug -----------------------------------------");
}
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="length"></param>
/// <param name="opcode"></param>
/// <param name="err"></param>
int WebsocketReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode,
WebSocketClient.WEBSOCKET_RESULT_CODES err)
{
var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length);
if(rx.Length > 0)
ParseStreamRx(rx);
WSClient.ReceiveAsync();
return 1;
}
/// <summary>
/// Callback to catch possible errors in sending via the websocket
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
int WebsocketSendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result)
{
Debug.Console(1, this, "SendCallback result: {0}", result);
return 1;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ParseStreamRx(string message)
{
if(string.IsNullOrEmpty(message))
return;
Debug.Console(1, this, "Message RX: '{0}'", message);
try
{
var messageObj = JObject.Parse(message);
var type = messageObj["type"].Value<string>();
if (type == "hello")
{
ResetOrStartHearbeatTimer();
}
else if (type == "/system/heartbeat")
{
HandleHeartBeat(messageObj["content"]);
}
else if (type == "close")
{
WSClient.Disconnect();
ServerHeartbeatCheckTimer.Stop();
// Start the reconnect timer
StartReconnectTimer();
}
else
{
// Check path against Action dictionary
if (ActionDictionary.ContainsKey(type))
{
var action = ActionDictionary[type];
if (action is Action)
{
(action as Action)();
}
else if (action is PressAndHoldAction)
{
var stateString = messageObj["content"]["state"].Value<string>();
// Look for a button press event
if (!string.IsNullOrEmpty(stateString))
{
switch (stateString)
{
case "true":
{
if (!PushedActions.ContainsKey(type))
{
PushedActions.Add(type, new CTimer(o =>
{
(action as PressAndHoldAction)(false);
PushedActions.Remove(type);
}, null, ButtonHeartbeatInterval, ButtonHeartbeatInterval));
}
// Maybe add an else to reset the timer
break;
}
case "held":
{
if (!PushedActions.ContainsKey(type))
{
PushedActions[type].Reset(ButtonHeartbeatInterval, ButtonHeartbeatInterval);
}
return;
}
case "false":
{
if (PushedActions.ContainsKey(type))
{
PushedActions[type].Stop();
PushedActions.Remove(type);
}
break;
}
}
(action as PressAndHoldAction)(stateString == "true");
}
}
else if (action is Action<bool>)
{
var stateString = messageObj["content"]["state"].Value<string>();
if (!string.IsNullOrEmpty(stateString))
{
(action as Action<bool>)(stateString == "true");
}
}
else if (action is Action<ushort>)
{
(action as Action<ushort>)(messageObj["content"]["value"].Value<ushort>());
}
else if (action is Action<string>)
{
(action as Action<string>)(messageObj["content"]["value"].Value<string>());
}
else if (action is Action<SourceSelectMessageContent>)
{
(action as Action<SourceSelectMessageContent>)(messageObj["content"]
.ToObject<SourceSelectMessageContent>());
}
}
else
{
Debug.Console(1, this, "-- Warning: Incoming message has no registered handler");
}
}
}
catch (Exception err)
{
//Debug.Console(1, "SseMessageLengthBeforeFailureCount: {0}", SseMessageLengthBeforeFailureCount);
//SseMessageLengthBeforeFailureCount = 0;
Debug.Console(1, this, "Unable to parse message: {0}", err);
}
}
void TestHttpRequest(string s)
{
{
s = s.Trim();
if (string.IsNullOrEmpty(s))
{
PrintTestHttpRequestUsage();
return;
}
var tokens = s.Split(' ');
if (tokens.Length < 2)
{
CrestronConsole.ConsoleCommandResponse("Too few paramaters\r");
PrintTestHttpRequestUsage();
return;
}
try
{
var url = tokens[1];
if (tokens[0].ToLower() == "get")
{
var resp = new HttpClient().Get(url);
CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp);
}
else if (tokens[0].ToLower() == "post")
{
var resp = new HttpClient().Post(url, new byte[] { });
CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp);
}
else
{
CrestronConsole.ConsoleCommandResponse("Only get or post supported\r");
PrintTestHttpRequestUsage();
}
}
catch (HttpException e)
{
CrestronConsole.ConsoleCommandResponse("Exception in request:\r");
CrestronConsole.ConsoleCommandResponse("Response URL: {0}\r", e.Response.ResponseUrl);
CrestronConsole.ConsoleCommandResponse("Response Error Code: {0}\r", e.Response.Code);
CrestronConsole.ConsoleCommandResponse("Response body: {0}\r", e.Response.ContentString);
}
}
}
void PrintTestHttpRequestUsage()
{
CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r");
}
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Room.Cotija
{
public interface IDelayedConfiguration
{
event EventHandler<EventArgs> ConfigurationIsReady;
}
}

View File

@@ -1,379 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Cotija;
namespace PepperDash.Essentials
{
public class CotijaEssentialsHuddleSpaceRoomBridge : CotijaBridgeBase
{
public EssentialsHuddleSpaceRoom Room { get; private set; }
/// <summary>
///
/// </summary>
public override string RoomName
{
get
{
return Room.Name;
}
}
/// <summary>
///
/// </summary>
/// <param name="parent"></param>
/// <param name="room"></param>
public CotijaEssentialsHuddleSpaceRoomBridge(EssentialsHuddleSpaceRoom room):
base("mobileControlBridge-essentialsHuddle", "Essentials Mobile Control Bridge-Huddle")
{
Room = room;
}
/// <summary>
/// Override of base: calls base to add parent and then registers actions and events.
/// </summary>
/// <param name="parent"></param>
public override void AddParent(CotijaSystemController parent)
{
base.AddParent(parent);
// we add actions to the messaging system with a path, and a related action. Custom action
// content objects can be handled in the controller's LineReceived method - and perhaps other
// sub-controller parsing could be attached to these classes, so that the systemController
// doesn't need to know about everything.
// Source Changes and room off
Parent.AddAction(string.Format(@"/room/{0}/status", Room.Key), new Action(() => Room_RoomFullStatus(Room)));
Parent.AddAction(string.Format(@"/room/{0}/source", Room.Key), new Action<SourceSelectMessageContent>(c => Room.RunRouteAction(c.SourceListItem)));
Parent.AddAction(string.Format(@"/room/{0}/defaultsource", Room.Key), new Action(Room.RunDefaultRoute));
Parent.AddAction(string.Format(@"/room/{0}/masterVolumeLevel", Room.Key), new Action<ushort>(u =>
(Room.CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(u)));
Parent.AddAction(string.Format(@"/room/{0}/masterVolumeMuteToggle", Room.Key), new Action(() => Room.CurrentVolumeControls.MuteToggle()));
Parent.AddAction(string.Format(@"/room/{0}/shutdownStart", Room.Key), new Action(() => Room.StartShutdown(eShutdownType.Manual)));
Parent.AddAction(string.Format(@"/room/{0}/shutdownEnd", Room.Key), new Action(() => Room.ShutdownPromptTimer.Finish()));
Parent.AddAction(string.Format(@"/room/{0}/shutdownCancel", Room.Key), new Action(() => Room.ShutdownPromptTimer.Cancel()));
Room.CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange);
Room.CurrentVolumeDeviceChange += new EventHandler<VolumeDeviceChangeEventArgs>(Room_CurrentVolumeDeviceChange);
Room.OnFeedback.OutputChange += OnFeedback_OutputChange;
Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
Room.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted;
Room.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished;
Room.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled;
// Registers for initial volume events, if possible
var currentVolumeDevice = Room.CurrentVolumeControls;
if (currentVolumeDevice != null)
{
if (currentVolumeDevice is IBasicVolumeWithFeedback)
{
var newDev = currentVolumeDevice as IBasicVolumeWithFeedback;
newDev.MuteFeedback.OutputChange += VolumeLevelFeedback_OutputChange;
newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange;
}
}
}
/// <summary>
/// Handler for cancelled shutdown
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("state", "wasCancelled");
JObject message = new JObject();
message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
/// <summary>
/// Handler for when shutdown finishes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("state", "hasFinished");
JObject message = new JObject();
message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
/// <summary>
/// Handler for when shutdown starts
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ShutdownPromptTimer_HasStarted(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("state", "hasStarted");
roomStatus.Add("duration", Room.ShutdownPromptTimer.SecondsToCount);
JObject message = new JObject();
message.Add("type", "/room/shutdown/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
// equivalent JS message:
// Post( { type: '/room/status/', content: { shutdown: 'hasStarted', duration: Room.ShutdownPromptTimer.SecondsToCount })
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void IsWarmingUpFeedback_OutputChange(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("isWarmingUp", (sender as BoolFeedback).BoolValue);
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void IsCoolingDownFeedback_OutputChange(object sender, EventArgs e)
{
JObject roomStatus = new JObject();
roomStatus.Add("isCoolingDown", (sender as BoolFeedback).BoolValue);
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void OnFeedback_OutputChange(object sender, EventArgs e)
{
/* Example message
* {
"type":"/room/status",
"content": {
"isOn": false
}
}
*/
JObject roomStatus = new JObject();
roomStatus.Add("isOn", (sender as BoolFeedback).BoolValue);
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e)
{
if (e.OldDev is IBasicVolumeWithFeedback)
{
var oldDev = e.OldDev as IBasicVolumeWithFeedback;
oldDev.MuteFeedback.OutputChange -= VolumeLevelFeedback_OutputChange;
oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange;
}
if (e.NewDev is IBasicVolumeWithFeedback)
{
var newDev = e.NewDev as IBasicVolumeWithFeedback;
newDev.MuteFeedback.OutputChange += VolumeLevelFeedback_OutputChange;
newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange;
}
}
void VolumeLevelFeedback_OutputChange(object sender, EventArgs e)
{
/* Example message
* {
"type":"/room/status",
"content": {
"masterVolumeLevel": 12345,
"masterVolumeMuteState": false
}
}
*/
var huddleRoom = Room as EssentialsHuddleSpaceRoom;
if(huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback)
{
JObject roomStatus = new JObject();
if (huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var currentVolumeConstrols = huddleRoom.CurrentVolumeControls as IBasicVolumeWithFeedback;
roomStatus.Add("masterVolumeLevel", currentVolumeConstrols.VolumeLevelFeedback.IntValue);
roomStatus.Add("masterVolumeMuteState", currentVolumeConstrols.MuteFeedback.BoolValue);
}
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
}
void Room_CurrentSingleSourceChange(EssentialsRoomBase room, PepperDash.Essentials.Core.SourceListItem info, ChangeType type)
{
/* Example message
* {
"type":"/room/status",
"content": {
"selectedSourceKey": "off",
}
}
*/
if (type == ChangeType.WillChange)
{
// Disconnect from previous source
if (info != null)
{
var previousDev = info.SourceDevice;
// device type interfaces
if (previousDev is ISetTopBoxControls)
(previousDev as ISetTopBoxControls).UnlinkActions(Parent);
// common interfaces
if (previousDev is IChannel)
(previousDev as IChannel).UnlinkActions(Parent);
if (previousDev is IColor)
(previousDev as IColor).UnlinkActions(Parent);
if (previousDev is IDPad)
(previousDev as IDPad).UnlinkActions(Parent);
if (previousDev is IDvr)
(previousDev as IDvr).UnlinkActions(Parent);
if (previousDev is INumericKeypad)
(previousDev as INumericKeypad).UnlinkActions(Parent);
if (previousDev is IPower)
(previousDev as IPower).UnlinkActions(Parent);
if (previousDev is ITransport)
(previousDev as ITransport).UnlinkActions(Parent);
}
}
else // did change
{
if (info != null)
{
var dev = info.SourceDevice;
if (dev is ISetTopBoxControls)
(dev as ISetTopBoxControls).LinkActions(Parent);
if (dev is IChannel)
(dev as IChannel).LinkActions(Parent);
if (dev is IColor)
(dev as IColor).LinkActions(Parent);
if (dev is IDPad)
(dev as IDPad).LinkActions(Parent);
if (dev is IDvr)
(dev as IDvr).LinkActions(Parent);
if (dev is INumericKeypad)
(dev as INumericKeypad).LinkActions(Parent);
if (dev is IPower)
(dev as IPower).LinkActions(Parent);
if (dev is ITransport)
(dev as ITransport).LinkActions(Parent);
var huddleRoom = room as EssentialsHuddleSpaceRoom;
JObject roomStatus = new JObject();
roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey);
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
}
}
/// <summary>
/// Posts the full status of the room to the server
/// </summary>
/// <param name="room"></param>
void Room_RoomFullStatus(EssentialsRoomBase room)
{
/* Example message
* {
"type":"/room/status",
"content": {
"selectedSourceKey": "off",
"isOn": false,
"masterVolumeLevel": 50,
"masterVolumeMuteState": false
}
}
*/
JObject roomStatus = new JObject();
var huddleRoom = room as EssentialsHuddleSpaceRoom;
roomStatus.Add("isOn", huddleRoom.OnFeedback.BoolValue);
roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey);
if(huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var currentVolumeConstrols = huddleRoom.CurrentVolumeControls as IBasicVolumeWithFeedback;
roomStatus.Add("masterVolumeLevel", currentVolumeConstrols.VolumeLevelFeedback.IntValue);
roomStatus.Add("masterVolumeMuteState", currentVolumeConstrols.MuteFeedback.BoolValue);
}
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.SendMessageToServer(message);
}
}
public class SourceSelectMessageContent
{
public string SourceListItem { get; set; }
//public string Destination { get; set; }
//public string SourceSelect { get; set; }
}
public delegate void PressAndHoldAction(bool b);
}

View File

@@ -1,462 +1,505 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
protected override Func<bool> OnFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
var val = CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route
&& disp != null;
//&& disp.PowerIsOnFeedback.BoolValue;
return val;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsWarmingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsWarmingUpFeedback.BoolValue;
else
return false;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsCoolingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsCoolingDownFeedback.BoolValue;
else
return false;
};
}
}
public EssentialsRoomPropertiesConfig Config { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
public string DefaultSourceItem { get; set; }
public ushort DefaultVolume { get; set; }
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
string LastSourceKey;
/// <summary>
///
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return _CurrentAudioDevice; }
set
{
if (value == _CurrentAudioDevice) return;
var oldDev = _CurrentAudioDevice;
// derigister this room from the device, if it can
if (oldDev is IInUseTracking)
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
var handler = CurrentVolumeDeviceChange;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
_CurrentAudioDevice = value;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// register this room with new device, if it can
if (_CurrentAudioDevice is IInUseTracking)
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
}
}
IBasicVolumeControls _CurrentAudioDevice;
/// <summary>
/// The SourceListItem last run - containing names and icons
/// </summary>
public SourceListItem CurrentSourceInfo
{
get { return _CurrentSourceInfo; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// remove from in-use tracker, if so equipped
if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(this, _CurrentSourceInfo, ChangeType.WillChange);
_CurrentSourceInfo = value;
// add to in-use tracking
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsHuddleSpaceRoom(string key, string name, IRoutingSinkWithSwitching defaultDisplay,
IRoutingSinkNoSwitching defaultAudio, EssentialsRoomPropertiesConfig config)
: base(key, name)
{
Config = config;
DefaultDisplay = defaultDisplay;
DefaultAudioDevice = defaultAudio;
if (defaultAudio is IBasicVolumeControls)
DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
else if (defaultAudio is IHasVolumeDevice)
DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
};
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
}
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
SetDefaultLevels();
RunDefaultRoute();
CrestronEnvironment.Sleep(1000);
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any
/// </summary>
public void RunDefaultRoute()
{
//if (DefaultSourceItem != null && !OnFeedback.BoolValue)
RunRouteAction(DefaultSourceItem);
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
public void RunRouteAction(string routeKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
{
Debug.Console(1, this, "Run route action '{0}'", routeKey);
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
if(dict == null)
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
return;
}
// Try to get the list item by it's string key
if (!dict.ContainsKey(routeKey))
{
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
routeKey, SourceListKey);
return;
}
var item = dict[routeKey];
//Debug.Console(2, this, "Action {0} has {1} steps",
// item.SourceKey, item.RouteList.Count);
// End usage timer on last source
if (!string.IsNullOrEmpty(LastSourceKey))
{
var lastSource = dict[LastSourceKey].SourceDevice;
try
{
if (lastSource != null && lastSource is IUsageTracking)
(lastSource as IUsageTracking).UsageTracker.EndDeviceUsage();
}
catch (Exception e)
{
Debug.Console(1, this, "*#* EXCEPTION in end usage tracking (257):\r{0}", e);
}
}
// Let's run it
if (routeKey.ToLower() != "roomoff")
{
LastSourceKey = routeKey;
}
else
{
CurrentSourceInfoKey = null;
}
foreach (var route in item.RouteList)
{
// if there is a $defaultAll on route, run two separate
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
{
// Going to assume a single-path route for now
var tempVideo = new SourceRouteListItem
{
DestinationKey = "$defaultDisplay",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
DoRoute(tempVideo);
//var tempAudio = new SourceRouteListItem
//{
// DestinationKey = "$defaultAudio",
// SourceKey = route.SourceKey,
// Type = eRoutingSignalType.Audio
//};
//DoRoute(tempAudio);
//continue; -- not sure why this was here
}
else
DoRoute(route);
}
// Start usage timer on routed source
if (item.SourceDevice is IUsageTracking)
{
(item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
}
// Set volume control, using default if non provided
IBasicVolumeControls volDev = null;
// Handle special cases for volume control
if (string.IsNullOrEmpty(item.VolumeControlKey)
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
volDev = DefaultVolumeControls;
else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
volDev = DefaultDisplay as IBasicVolumeControls;
// Or a specific device, probably rarely used.
else
{
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
if (dev is IBasicVolumeControls)
volDev = dev as IBasicVolumeControls;
else if (dev is IHasVolumeDevice)
volDev = (dev as IHasVolumeDevice).VolumeDevice;
}
if (volDev != CurrentVolumeControls)
{
// zero the volume on the device we are leaving.
// Set the volume to default on device we are entering
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue;
vd.SetVolume(0);
}
CurrentVolumeControls = volDev;
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
vd.SetVolume(vol);
}
}
// store the name and UI info for routes
if (item.SourceKey == "$off")
{
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = null;
}
else if (item.SourceKey != null)
{
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = item;
}
// And finally, set the "control". This will trigger event
//CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device;
OnFeedback.FireUpdate();
// report back when done
if (successCallback != null)
successCallback();
}, 0); // end of CTimer
}
/// <summary>
/// Will power the room on with the last-used source
/// </summary>
public void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(1, this, "Restoring default levels");
var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
if (vc != null)
vc.SetVolume(DefaultVolume);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSinkNoSwitching dest = null;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
dest = DefaultAudioDevice;
else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
dest = DefaultDisplay;
else
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching;
if (dest == null)
{
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
return false;
}
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IPower)
(dest as IPower).PowerOff();
}
else
{
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
return false;
}
dest.ReleaseAndMakeRoute(source, route.Type);
}
return true;
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
}
/// <summary>
/// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
/// </summary>
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
protected override Func<bool> OnFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
var val = CurrentSourceInfo != null
&& CurrentSourceInfo.Type == eSourceListItemType.Route
&& disp != null;
//&& disp.PowerIsOnFeedback.BoolValue;
return val;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsWarmingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsWarmingUpFeedback.BoolValue;
else
return false;
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsCoolingFeedbackFunc
{
get
{
return () =>
{
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
return disp.IsCoolingDownFeedback.BoolValue;
else
return false;
};
}
}
public EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; private set; }
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
public string DefaultSourceItem { get; set; }
public ushort DefaultVolume { get; set; }
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
string LastSourceKey;
/// <summary>
///
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return _CurrentAudioDevice; }
set
{
if (value == _CurrentAudioDevice) return;
var oldDev = _CurrentAudioDevice;
// derigister this room from the device, if it can
if (oldDev is IInUseTracking)
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
var handler = CurrentVolumeDeviceChange;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
_CurrentAudioDevice = value;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// register this room with new device, if it can
if (_CurrentAudioDevice is IInUseTracking)
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
}
}
IBasicVolumeControls _CurrentAudioDevice;
/// <summary>
/// The SourceListItem last run - containing names and icons
/// </summary>
public SourceListItem CurrentSourceInfo
{
get { return _CurrentSourceInfo; }
private set
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
// remove from in-use tracker, if so equipped
if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(this, _CurrentSourceInfo, ChangeType.WillChange);
_CurrentSourceInfo = value;
// add to in-use tracking
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(this, _CurrentSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
public EssentialsHuddleSpaceRoom(DeviceConfig config)
: base(config)
{
try
{
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>
(config.Properties.ToString());
DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IRoutingSinkWithSwitching;
Initialize();
}
catch (Exception e)
{
Debug.Console(1, this, "Error building room: \n{0}", e);
}
}
void Initialize()
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
else if (DefaultAudioDevice is IHasVolumeDevice)
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
var disp = DefaultDisplay as DisplayBase;
if (disp != null)
{
// Link power, warming, cooling to display
disp.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!disp.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
};
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
}
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleRoomPropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateRoomConfig(config);
}
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
SetDefaultLevels();
RunDefaultPresentRoute();
CrestronEnvironment.Sleep(1000);
RunRouteAction("roomOff");
}
/// <summary>
/// Routes the default source item, if any
/// </summary>
public override bool RunDefaultPresentRoute()
{
if (DefaultSourceItem == null)
{
Debug.Console(0, this, "Unable to run default present route, DefaultSourceItem is null.");
return false;
}
RunRouteAction(DefaultSourceItem);
return true;
}
public override bool CustomActivate()
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
this.SourceListKey = PropertiesConfig.SourceListKey;
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
return base.CustomActivate();
}
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
public void RunRouteAction(string routeKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
{
Debug.Console(1, this, "Run route action '{0}'", routeKey);
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
if(dict == null)
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
return;
}
// Try to get the list item by it's string key
if (!dict.ContainsKey(routeKey))
{
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
routeKey, SourceListKey);
return;
}
var item = dict[routeKey];
//Debug.Console(2, this, "Action {0} has {1} steps",
// item.SourceKey, item.RouteList.Count);
// End usage timer on last source
if (!string.IsNullOrEmpty(LastSourceKey))
{
var lastSource = dict[LastSourceKey].SourceDevice;
try
{
if (lastSource != null && lastSource is IUsageTracking)
(lastSource as IUsageTracking).UsageTracker.EndDeviceUsage();
}
catch (Exception e)
{
Debug.Console(1, this, "*#* EXCEPTION in end usage tracking (257):\r{0}", e);
}
}
// Let's run it
if (routeKey.ToLower() != "roomoff")
{
LastSourceKey = routeKey;
}
else
{
CurrentSourceInfoKey = null;
}
foreach (var route in item.RouteList)
{
// if there is a $defaultAll on route, run two separate
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
{
// Going to assume a single-path route for now
var tempVideo = new SourceRouteListItem
{
DestinationKey = "$defaultDisplay",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
DoRoute(tempVideo);
//var tempAudio = new SourceRouteListItem
//{
// DestinationKey = "$defaultAudio",
// SourceKey = route.SourceKey,
// Type = eRoutingSignalType.Audio
//};
//DoRoute(tempAudio);
//continue; -- not sure why this was here
}
else
DoRoute(route);
}
// Start usage timer on routed source
if (item.SourceDevice is IUsageTracking)
{
(item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
}
// Set volume control, using default if non provided
IBasicVolumeControls volDev = null;
// Handle special cases for volume control
if (string.IsNullOrEmpty(item.VolumeControlKey)
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
volDev = DefaultVolumeControls;
else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
volDev = DefaultDisplay as IBasicVolumeControls;
// Or a specific device, probably rarely used.
else
{
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
if (dev is IBasicVolumeControls)
volDev = dev as IBasicVolumeControls;
else if (dev is IHasVolumeDevice)
volDev = (dev as IHasVolumeDevice).VolumeDevice;
}
if (volDev != CurrentVolumeControls)
{
// zero the volume on the device we are leaving.
// Set the volume to default on device we are entering
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue;
vd.SetVolume(0);
}
CurrentVolumeControls = volDev;
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
vd.SetVolume(vol);
}
}
// store the name and UI info for routes
if (item.SourceKey == "$off")
{
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = null;
}
else if (item.SourceKey != null)
{
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = item;
}
// And finally, set the "control". This will trigger event
//CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device;
OnFeedback.FireUpdate();
// report back when done
if (successCallback != null)
successCallback();
}, 0); // end of CTimer
}
/// <summary>
/// Will power the room on with the last-used source
/// </summary>
public override void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(1, this, "Restoring default levels");
var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
if (vc != null)
vc.SetVolume(DefaultVolume);
}
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSinkNoSwitching dest = null;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
dest = DefaultAudioDevice;
else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
dest = DefaultDisplay;
else
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching;
if (dest == null)
{
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
return false;
}
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IPower)
(dest as IPower).PowerOff();
}
else
{
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
return false;
}
dest.ReleaseAndMakeRoute(source, route.Type);
}
return true;
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
}
/// <summary>
/// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
/// </summary>
public static void AllRoomsOff()
{
var allRooms = DeviceManager.AllDevices.Where(d =>
d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
foreach (var room in allRooms)
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,437 +1,437 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
//using PepperDash.Core;
//using PepperDash.Essentials.Core;
//using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsPresentationRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
public event SourceInfoChangeHandler CurrentDisplay1SourceChange;
public event SourceInfoChangeHandler CurrentDisplay2SourceChange;
//namespace PepperDash.Essentials
//{
// public class EssentialsPresentationRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange
// {
// public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
// public event SourceInfoChangeHandler CurrentSingleSourceChange;
// public event SourceInfoChangeHandler CurrentDisplay1SourceChange;
// public event SourceInfoChangeHandler CurrentDisplay2SourceChange;
protected override Func<bool> OnFeedbackFunc { get {
return () => (CurrentSingleSourceInfo != null
&& CurrentSingleSourceInfo.Type != eSourceListItemType.Off)
|| (Display1SourceInfo != null
&& Display1SourceInfo.Type != eSourceListItemType.Off)
|| (Display2SourceInfo != null
&& Display2SourceInfo.Type != eSourceListItemType.Off); } }
// protected override Func<bool> OnFeedbackFunc { get {
// return () => (CurrentSingleSourceInfo != null
// && CurrentSingleSourceInfo.Type != eSourceListItemType.Off)
// || (Display1SourceInfo != null
// && Display1SourceInfo.Type != eSourceListItemType.Off)
// || (Display2SourceInfo != null
// && Display2SourceInfo.Type != eSourceListItemType.Off); } }
protected override Func<bool> IsWarmingFeedbackFunc { get { return () =>false;; } }
protected override Func<bool> IsCoolingFeedbackFunc { get { return () => false; } }
// protected override Func<bool> IsWarmingFeedbackFunc { get { return () =>false;; } }
// protected override Func<bool> IsCoolingFeedbackFunc { get { return () => false; } }
public EssentialsPresentationRoomPropertiesConfig Config { get; private set; }
// public EssentialsPresentationRoomPropertiesConfig Config { get; private set; }
public Dictionary<uint, IRoutingSinkNoSwitching> Displays { get; private set; }
// public Dictionary<uint, IRoutingSinkNoSwitching> Displays { get; private set; }
public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
// public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; }
// public IBasicVolumeControls DefaultVolumeControls { get; private set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
// /// <summary>
// /// The config name of the source list
// /// </summary>
// public string SourceListKey { get; set; }
/// <summary>
/// If room is off, enables power on to last source. Default true
/// </summary>
public bool EnablePowerOnToLastSource { get; set; }
string LastSourceKey;
// /// <summary>
// /// If room is off, enables power on to last source. Default true
// /// </summary>
// public bool EnablePowerOnToLastSource { get; set; }
// string LastSourceKey;
public enum eVideoRoutingMode
{
SelectSourceSelectDisplay, SourceToAllDisplays
}
// public enum eVideoRoutingMode
// {
// SelectSourceSelectDisplay, SourceToAllDisplays
// }
public eVideoRoutingMode VideoRoutingMode { get; set; }
// public eVideoRoutingMode VideoRoutingMode { get; set; }
public enum eAudioRoutingMode
{
AudioFollowsLastVideo, SelectAudioFromDisplay
}
// public enum eAudioRoutingMode
// {
// AudioFollowsLastVideo, SelectAudioFromDisplay
// }
/// <summary>
///
/// </summary>
public IBasicVolumeControls CurrentVolumeControls
{
get { return _CurrentAudioDevice; }
set
{
if (value == _CurrentAudioDevice) return;
// /// <summary>
// ///
// /// </summary>
// public IBasicVolumeControls CurrentVolumeControls
// {
// get { return _CurrentAudioDevice; }
// set
// {
// if (value == _CurrentAudioDevice) return;
var oldDev = _CurrentAudioDevice;
// derigister this room from the device, if it can
if (oldDev is IInUseTracking)
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
var handler = CurrentVolumeDeviceChange;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
_CurrentAudioDevice = value;
if (handler != null)
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// register this room with new device, if it can
if (_CurrentAudioDevice is IInUseTracking)
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
}
}
IBasicVolumeControls _CurrentAudioDevice;
// var oldDev = _CurrentAudioDevice;
// // derigister this room from the device, if it can
// if (oldDev is IInUseTracking)
// (oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
// var handler = CurrentVolumeDeviceChange;
// if (handler != null)
// CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
// _CurrentAudioDevice = value;
// if (handler != null)
// CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
// // register this room with new device, if it can
// if (_CurrentAudioDevice is IInUseTracking)
// (_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
// }
// }
// IBasicVolumeControls _CurrentAudioDevice;
/// <summary>
/// The SourceListItem last run - containing names and icons. The complex setter is
/// to add/remove this room to the source's InUseTracking, if it is capable
/// </summary>
public SourceListItem CurrentSingleSourceInfo
{
get { return _CurrentSingleSourceInfo; }
private set
{
if (value == _CurrentSingleSourceInfo) return;
// /// <summary>
// /// The SourceListItem last run - containing names and icons. The complex setter is
// /// to add/remove this room to the source's InUseTracking, if it is capable
// /// </summary>
// public SourceListItem CurrentSingleSourceInfo
// {
// get { return _CurrentSingleSourceInfo; }
// private set
// {
// if (value == _CurrentSingleSourceInfo) return;
var handler = CurrentSingleSourceChange;
// remove from in-use tracker, if so equipped
if(_CurrentSingleSourceInfo != null && _CurrentSingleSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSingleSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
// var handler = CurrentSingleSourceChange;
// // remove from in-use tracker, if so equipped
// if(_CurrentSingleSourceInfo != null && _CurrentSingleSourceInfo.SourceDevice is IInUseTracking)
// (_CurrentSingleSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
if (handler != null)
handler(this, _CurrentSingleSourceInfo, ChangeType.WillChange);
// if (handler != null)
// handler(this, _CurrentSingleSourceInfo, ChangeType.WillChange);
_CurrentSingleSourceInfo = value;
// _CurrentSingleSourceInfo = value;
// add to in-use tracking
if (_CurrentSingleSourceInfo != null && _CurrentSingleSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSingleSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null)
handler(this, _CurrentSingleSourceInfo, ChangeType.DidChange);
}
}
SourceListItem _CurrentSingleSourceInfo;
// // add to in-use tracking
// if (_CurrentSingleSourceInfo != null && _CurrentSingleSourceInfo.SourceDevice is IInUseTracking)
// (_CurrentSingleSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
// if (handler != null)
// handler(this, _CurrentSingleSourceInfo, ChangeType.DidChange);
// }
// }
// SourceListItem _CurrentSingleSourceInfo;
public SourceListItem Display1SourceInfo
{
get { return _Display1SourceInfo; }
set
{
if (value == _Display1SourceInfo) return;
// public SourceListItem Display1SourceInfo
// {
// get { return _Display1SourceInfo; }
// set
// {
// if (value == _Display1SourceInfo) return;
var handler = CurrentDisplay1SourceChange;
if (handler != null)
handler(this, _Display1SourceInfo, ChangeType.WillChange);
// var handler = CurrentDisplay1SourceChange;
// if (handler != null)
// handler(this, _Display1SourceInfo, ChangeType.WillChange);
_Display1SourceInfo = value;
// _Display1SourceInfo = value;
if (handler != null)
handler(this, _Display1SourceInfo, ChangeType.DidChange);
}
}
SourceListItem _Display1SourceInfo;
// if (handler != null)
// handler(this, _Display1SourceInfo, ChangeType.DidChange);
// }
// }
// SourceListItem _Display1SourceInfo;
public SourceListItem Display2SourceInfo
{
get { return _Display2SourceInfo; }
set
{
if (value == _Display2SourceInfo) return;
// public SourceListItem Display2SourceInfo
// {
// get { return _Display2SourceInfo; }
// set
// {
// if (value == _Display2SourceInfo) return;
var handler = CurrentDisplay2SourceChange;
if (handler != null)
handler(this, _Display2SourceInfo, ChangeType.WillChange);
// var handler = CurrentDisplay2SourceChange;
// if (handler != null)
// handler(this, _Display2SourceInfo, ChangeType.WillChange);
_Display2SourceInfo = value;
// _Display2SourceInfo = value;
if (handler != null)
handler(this, _Display2SourceInfo, ChangeType.DidChange);
}
}
SourceListItem _Display2SourceInfo;
// if (handler != null)
// handler(this, _Display2SourceInfo, ChangeType.DidChange);
// }
// }
// SourceListItem _Display2SourceInfo;
/// <summary>
/// If an audio dialer is available for this room
/// </summary>
public bool HasAudioDialer { get { return false; } }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsPresentationRoom(string key, string name,
Dictionary<uint, IRoutingSinkNoSwitching> displays,
IBasicVolumeWithFeedback defaultVolume, EssentialsPresentationRoomPropertiesConfig config)
: base(key, name)
{
Config = config;
Displays = displays;
// /// <summary>
// /// If an audio dialer is available for this room
// /// </summary>
// public bool HasAudioDialer { get { return false; } }
// /// <summary>
// ///
// /// </summary>
// /// <param name="key"></param>
// /// <param name="name"></param>
// public EssentialsPresentationRoom(string key, string name,
// Dictionary<uint, IRoutingSinkNoSwitching> displays,
// IBasicVolumeWithFeedback defaultVolume, EssentialsPresentationRoomPropertiesConfig config)
// : base(key, name)
// {
// Config = config;
// Displays = displays;
DefaultVolumeControls = defaultVolume;
CurrentVolumeControls = defaultVolume;
// DefaultVolumeControls = defaultVolume;
// CurrentVolumeControls = defaultVolume;
//DefaultAudioDevice = defaultAudio;
//if (defaultAudio is IBasicVolumeControls)
// DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
//else if (defaultAudio is IHasVolumeDevice)
// DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
// //DefaultAudioDevice = defaultAudio;
// //if (defaultAudio is IBasicVolumeControls)
// // DefaultVolumeControls = defaultAudio as IBasicVolumeControls;
// //else if (defaultAudio is IHasVolumeDevice)
// // DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice;
SourceListKey = "default";
EnablePowerOnToLastSource = true;
}
// SourceListKey = "default";
// EnablePowerOnToLastSource = true;
// }
/// <summary>
/// Run the same source to all destinations
/// </summary>
/// <param name="sourceItem"></param>
public void RouteSourceToAllDestinations(SourceListItem sourceItem)
{
if (Config.Volumes.Master != null)
{
var audioDev = DeviceManager.GetDeviceForKey(Config.Volumes.Master.DeviceKey);
if (audioDev is IBasicVolumeWithFeedback)
{
// /// <summary>
// /// Run the same source to all destinations
// /// </summary>
// /// <param name="sourceItem"></param>
// public void RouteSourceToAllDestinations(SourceListItem sourceItem)
// {
// if (Config.Volumes.Master != null)
// {
// var audioDev = DeviceManager.GetDeviceForKey(Config.Volumes.Master.DeviceKey);
// if (audioDev is IBasicVolumeWithFeedback)
// {
}
}
// }
// }
foreach (var display in Displays.Values)
{
if (sourceItem != null)
DoVideoRoute(sourceItem.SourceKey, display.Key);
else
DoVideoRoute("$off", display.Key);
}
Display1SourceInfo = sourceItem;
Display2SourceInfo = sourceItem;
CurrentSingleSourceInfo = sourceItem;
OnFeedback.FireUpdate();
}
// foreach (var display in Displays.Values)
// {
// if (sourceItem != null)
// DoVideoRoute(sourceItem.SourceKey, display.Key);
// else
// DoVideoRoute("$off", display.Key);
// }
// Display1SourceInfo = sourceItem;
// Display2SourceInfo = sourceItem;
// CurrentSingleSourceInfo = sourceItem;
// OnFeedback.FireUpdate();
// }
public void SourceToDisplay1(SourceListItem sourceItem)
{
DoVideoRoute(sourceItem.SourceKey, Displays[1].Key);
Display1SourceInfo = sourceItem;
OnFeedback.FireUpdate();
}
// public void SourceToDisplay1(SourceListItem sourceItem)
// {
// DoVideoRoute(sourceItem.SourceKey, Displays[1].Key);
// Display1SourceInfo = sourceItem;
// OnFeedback.FireUpdate();
// }
public void SourceToDisplay2(SourceListItem sourceItem)
{
DoVideoRoute(sourceItem.SourceKey, Displays[2].Key);
Display2SourceInfo = sourceItem;
OnFeedback.FireUpdate();
}
// public void SourceToDisplay2(SourceListItem sourceItem)
// {
// DoVideoRoute(sourceItem.SourceKey, Displays[2].Key);
// Display2SourceInfo = sourceItem;
// OnFeedback.FireUpdate();
// }
/// <summary>
/// Basic source -> destination routing
/// </summary>
void DoVideoRoute(string sourceKey, string destinationKey)
{
new CTimer(o =>
{
var dest = DeviceManager.GetDeviceForKey(destinationKey) as IRoutingSinkNoSwitching;
if (dest == null)
{
Debug.Console(1, this, "Cannot route. Destination '{0}' not found", destinationKey);
return;
}
// off is special case
if (sourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IPower)
(dest as IPower).PowerOff();
return;
}
// /// <summary>
// /// Basic source -> destination routing
// /// </summary>
// void DoVideoRoute(string sourceKey, string destinationKey)
// {
// new CTimer(o =>
// {
// var dest = DeviceManager.GetDeviceForKey(destinationKey) as IRoutingSinkNoSwitching;
// if (dest == null)
// {
// Debug.Console(1, this, "Cannot route. Destination '{0}' not found", destinationKey);
// return;
// }
// // off is special case
// if (sourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
// {
// dest.ReleaseRoute();
// if (dest is IPower)
// (dest as IPower).PowerOff();
// return;
// }
var source = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route. Source '{0}' not found", sourceKey);
return;
}
dest.ReleaseAndMakeRoute(source, eRoutingSignalType.Video);
}, 0);
}
// var source = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs;
// if (source == null)
// {
// Debug.Console(1, this, "Cannot route. Source '{0}' not found", sourceKey);
// return;
// }
// dest.ReleaseAndMakeRoute(source, eRoutingSignalType.Video);
// }, 0);
// }
/// <summary>
///
/// </summary>
protected override void EndShutdown()
{
RunRouteAction("roomoff");
}
// /// <summary>
// ///
// /// </summary>
// protected override void EndShutdown()
// {
// RunRouteAction("roomoff");
// }
/// <summary>
///
/// </summary>
/// <param name="routeKey"></param>
public void RunRouteAction(string routeKey)
{
RunRouteAction(routeKey, null);
}
// /// <summary>
// ///
// /// </summary>
// /// <param name="routeKey"></param>
// public void RunRouteAction(string routeKey)
// {
// RunRouteAction(routeKey, null);
// }
/// <summary>
/// Gets a source from config list SourceListKey and dynamically build and executes the
/// route or commands
/// </summary>
/// <param name="name"></param>
public void RunRouteAction(string routeKey, Action successCallback)
{
// Run this on a separate thread
new CTimer(o =>
{
Debug.Console(1, this, "Run room action '{0}'", routeKey);
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
if(dict == null)
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
return;
}
// /// <summary>
// /// Gets a source from config list SourceListKey and dynamically build and executes the
// /// route or commands
// /// </summary>
// /// <param name="name"></param>
// public void RunRouteAction(string routeKey, Action successCallback)
// {
// // Run this on a separate thread
// new CTimer(o =>
// {
// Debug.Console(1, this, "Run room action '{0}'", routeKey);
// var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
// if(dict == null)
// {
// Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
// return;
// }
// Try to get the list item by it's string key
if (!dict.ContainsKey(routeKey))
{
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
routeKey, SourceListKey);
return;
}
// // Try to get the list item by it's string key
// if (!dict.ContainsKey(routeKey))
// {
// Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
// routeKey, SourceListKey);
// return;
// }
var item = dict[routeKey];
//Debug.Console(2, this, "Action {0} has {1} steps",
// item.SourceKey, item.RouteList.Count);
// var item = dict[routeKey];
// //Debug.Console(2, this, "Action {0} has {1} steps",
// // item.SourceKey, item.RouteList.Count);
// Let's run it
if (routeKey.ToLower() != "roomoff")
LastSourceKey = routeKey;
// // Let's run it
// if (routeKey.ToLower() != "roomoff")
// LastSourceKey = routeKey;
foreach (var route in item.RouteList)
{
// if there is a $defaultAll on route, run two separate
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
{
var tempAudio = new SourceRouteListItem
{
DestinationKey = "$defaultDisplay",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Video
};
DoRoute(tempAudio);
// foreach (var route in item.RouteList)
// {
// // if there is a $defaultAll on route, run two separate
// if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
// {
// var tempAudio = new SourceRouteListItem
// {
// DestinationKey = "$defaultDisplay",
// SourceKey = route.SourceKey,
// Type = eRoutingSignalType.Video
// };
// DoRoute(tempAudio);
var tempVideo = new SourceRouteListItem
{
DestinationKey = "$defaultAudio",
SourceKey = route.SourceKey,
Type = eRoutingSignalType.Audio
};
DoRoute(tempVideo);
continue;
}
else
DoRoute(route);
}
// var tempVideo = new SourceRouteListItem
// {
// DestinationKey = "$defaultAudio",
// SourceKey = route.SourceKey,
// Type = eRoutingSignalType.Audio
// };
// DoRoute(tempVideo);
// continue;
// }
// else
// DoRoute(route);
// }
// Set volume control on room, using default if non provided
IBasicVolumeControls volDev = null;
// Handle special cases for volume control
if (string.IsNullOrEmpty(item.VolumeControlKey)
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
volDev = DefaultVolumeControls;
//else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
// volDev = DefaultDisplay as IBasicVolumeControls;
// Or a specific device, probably rarely used.
else
{
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
if (dev is IBasicVolumeControls)
volDev = dev as IBasicVolumeControls;
else if (dev is IHasVolumeDevice)
volDev = (dev as IHasVolumeDevice).VolumeDevice;
}
CurrentVolumeControls = volDev;
// // Set volume control on room, using default if non provided
// IBasicVolumeControls volDev = null;
// // Handle special cases for volume control
// if (string.IsNullOrEmpty(item.VolumeControlKey)
// || item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
// volDev = DefaultVolumeControls;
// //else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
// // volDev = DefaultDisplay as IBasicVolumeControls;
// // Or a specific device, probably rarely used.
// else
// {
// var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
// if (dev is IBasicVolumeControls)
// volDev = dev as IBasicVolumeControls;
// else if (dev is IHasVolumeDevice)
// volDev = (dev as IHasVolumeDevice).VolumeDevice;
// }
// CurrentVolumeControls = volDev;
// store the name and UI info for routes
if (item.SourceKey != null)
CurrentSingleSourceInfo = item;
// And finally, set the "control". This will trigger event
//CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device;
// // store the name and UI info for routes
// if (item.SourceKey != null)
// CurrentSingleSourceInfo = item;
// // And finally, set the "control". This will trigger event
// //CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device;
OnFeedback.FireUpdate();
// OnFeedback.FireUpdate();
// report back when done
if (successCallback != null)
successCallback();
}, 0); // end of CTimer
}
// // report back when done
// if (successCallback != null)
// successCallback();
// }, 0); // end of CTimer
// }
/// <summary>
/// Will power the room on with the last-used source
/// </summary>
public void PowerOnToDefaultOrLastSource()
{
if (!EnablePowerOnToLastSource || LastSourceKey == null)
return;
RunRouteAction(LastSourceKey);
}
// /// <summary>
// /// Will power the room on with the last-used source
// /// </summary>
// public void PowerOnToDefaultOrLastSource()
// {
// if (!EnablePowerOnToLastSource || LastSourceKey == null)
// return;
// RunRouteAction(LastSourceKey);
// }
/// <summary>
/// Does what it says
/// </summary>
public override void SetDefaultLevels()
{
Debug.Console(0, this, "SetDefaultLevels not implemented");
}
// /// <summary>
// /// Does what it says
// /// </summary>
// public override void SetDefaultLevels()
// {
// Debug.Console(0, this, "SetDefaultLevels not implemented");
// }
/// <summary>
///
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
bool DoRoute(SourceRouteListItem route)
{
IRoutingSinkNoSwitching dest = null;
// /// <summary>
// ///
// /// </summary>
// /// <param name="route"></param>
// /// <returns></returns>
// bool DoRoute(SourceRouteListItem route)
// {
// IRoutingSinkNoSwitching dest = null;
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
dest = DefaultAudioDevice;
//else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
// dest = DefaultDisplay;
else
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching;
// if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
// dest = DefaultAudioDevice;
// //else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
// // dest = DefaultDisplay;
// else
// dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching;
if (dest == null)
{
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
return false;
}
// if (dest == null)
// {
// Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
// return false;
// }
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
{
dest.ReleaseRoute();
if (dest is IPower)
(dest as IPower).PowerOff();
}
else
{
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
if (source == null)
{
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
return false;
}
dest.ReleaseAndMakeRoute(source, route.Type);
}
return true;
}
// if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
// {
// dest.ReleaseRoute();
// if (dest is IPower)
// (dest as IPower).PowerOff();
// }
// else
// {
// var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
// if (source == null)
// {
// Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
// return false;
// }
// dest.ReleaseAndMakeRoute(source, route.Type);
// }
// return true;
// }
public override void RoomVacatedForTimeoutPeriod(object o)
{
//Implement this
}
// public override void RoomVacatedForTimeoutPeriod(object o)
// {
// //Implement this
// }
}
}
// }
//}

View File

@@ -1,272 +1,297 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Occupancy;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public interface IHasCurrentSourceInfoChange
{
event SourceInfoChangeHandler CurrentSingleSourceChange;
}
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : Device
{
/// <summary>
///
/// </summary>
public BoolFeedback OnFeedback { get; private set; }
public BoolFeedback IsWarmingUpFeedback { get; private set; }
public BoolFeedback IsCoolingDownFeedback { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; private set; }
public bool OccupancyStatusProviderIsRemote { get; private set; }
protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
/// <summary>
/// Timer used for informing the UIs of a shutdown
/// </summary>
public SecondsCountdownTimer ShutdownPromptTimer { get; private set; }
/// <summary>
///
/// </summary>
public int ShutdownPromptSeconds { get; set; }
public int ShutdownVacancySeconds { get; set; }
public eShutdownType ShutdownType { get; private set; }
public PepperDash.Essentials.Room.EssentialsRoomEmergencyBase Emergency { get; set; }
public PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrl { get; set; }
protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; }
public eVacancyMode VacancyMode { get; private set; }
/// <summary>
/// Seconds after vacancy prompt is displayed until shutdown
/// </summary>
protected int RoomVacancyShutdownSeconds;
/// <summary>
/// Seconds after vacancy detected until prompt is displayed
/// </summary>
protected int RoomVacancyShutdownPromptSeconds;
/// <summary>
///
/// </summary>
protected abstract Func<bool> OnFeedbackFunc { get; }
protected Dictionary<IBasicVolumeWithFeedback, uint> SavedVolumeLevels = new Dictionary<IBasicVolumeWithFeedback, uint>();
/// <summary>
/// When volume control devices change, should we zero the one that we are leaving?
/// </summary>
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssentialsRoomBase(string key, string name) : base(key, name)
{
// Setup the ShutdownPromptTimer
ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer");
ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) =>
{
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
ShutdownType = eShutdownType.None;
};
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
ShutdownPromptSeconds = 60;
ShutdownVacancySeconds = 120;
ShutdownType = eShutdownType.None;
RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer");
//RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) =>
//{
// if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue)
// ShutdownType = ShutdownType.Vacancy;
//};
RoomVacancyShutdownTimer.HasFinished += new EventHandler<EventArgs>(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered
RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning
RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt
VacancyMode = eVacancyMode.None;
OnFeedback = new BoolFeedback(OnFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc);
IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc);
}
void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
switch (VacancyMode)
{
case eVacancyMode.None:
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
break;
case eVacancyMode.InInitialVacancy:
StartRoomVacancyTimer(eVacancyMode.InShutdownWarning);
break;
case eVacancyMode.InShutdownWarning:
{
StartShutdown(eShutdownType.Vacancy);
Debug.Console(0, this, "Shutting Down due to vacancy.");
break;
}
default:
break;
}
}
/// <summary>
///
/// </summary>
/// <param name="type"></param>
public void StartShutdown(eShutdownType type)
{
// Check for shutdowns running. Manual should override other shutdowns
if (type == eShutdownType.Manual)
ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds;
else if (type == eShutdownType.Vacancy)
ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds;
ShutdownType = type;
ShutdownPromptTimer.Start();
}
public void StartRoomVacancyTimer(eVacancyMode mode)
{
if (mode == eVacancyMode.None)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds;
else if (mode == eVacancyMode.InInitialVacancy)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds;
VacancyMode = mode;
RoomVacancyShutdownTimer.Start();
Debug.Console(0, this, "Vacancy Timer Started.");
}
/// <summary>
/// Resets the vacancy mode and shutsdwon the room
/// </summary>
public void Shutdown()
{
VacancyMode = eVacancyMode.None;
EndShutdown();
}
/// <summary>
/// This method is for the derived class to define it's specific shutdown
/// requirements but should not be called directly. It is called by Shutdown()
/// </summary>
protected abstract void EndShutdown();
/// <summary>
/// Override this to implement a default volume level(s) method
/// </summary>
public abstract void SetDefaultLevels();
/// <summary>
/// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device
/// </summary>
/// <param name="statusProvider"></param>
public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes)
{
if (statusProvider == null)
{
Debug.Console(0, this, "ERROR: Occupancy sensor device is null");
return;
}
// If status provider is fusion, set flag to remote
if (statusProvider is PepperDash.Essentials.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
OccupancyStatusProviderIsRemote = true;
if(timeoutMinutes > 0)
RoomVacancyShutdownSeconds = timeoutMinutes * 60;
RoomOccupancy = statusProvider;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
}
void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
{
Debug.Console(1, this, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
}
else
{
Debug.Console(1, this, "Notice: Occupancy Detected");
// Reset the timer when the room is occupied
RoomVacancyShutdownTimer.Cancel();
}
}
//void SwapVolumeDevices(IBasicVolumeControls currentDevice, IBasicVolumeControls newDevice)
//{
//}
/// <summary>
/// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed
/// </summary>
/// <param name="o"></param>
public abstract void RoomVacatedForTimeoutPeriod(object o);
}
/// <summary>
/// To describe the various ways a room may be shutting down
/// </summary>
public enum eShutdownType
{
None = 0,
External,
Manual,
Vacancy
}
public enum eVacancyMode
{
None = 0,
InInitialVacancy,
InShutdownWarning
}
/// <summary>
///
/// </summary>
public enum eWarmingCoolingMode
{
None,
Warming,
Cooling
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Occupancy;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : ReconfigurableDevice
{
/// <summary>
///
/// </summary>
public BoolFeedback OnFeedback { get; private set; }
/// <summary>
/// Fires when the RoomOccupancy object is set
/// </summary>
public event EventHandler<EventArgs> RoomOccupancyIsSet;
public BoolFeedback IsWarmingUpFeedback { get; private set; }
public BoolFeedback IsCoolingDownFeedback { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; private set; }
public bool OccupancyStatusProviderIsRemote { get; private set; }
protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
/// <summary>
/// Timer used for informing the UIs of a shutdown
/// </summary>
public SecondsCountdownTimer ShutdownPromptTimer { get; private set; }
/// <summary>
///
/// </summary>
public int ShutdownPromptSeconds { get; set; }
public int ShutdownVacancySeconds { get; set; }
public eShutdownType ShutdownType { get; private set; }
public PepperDash.Essentials.Room.EssentialsRoomEmergencyBase Emergency { get; set; }
public PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrl { get; set; }
protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; }
public eVacancyMode VacancyMode { get; private set; }
/// <summary>
/// Seconds after vacancy prompt is displayed until shutdown
/// </summary>
protected int RoomVacancyShutdownSeconds;
/// <summary>
/// Seconds after vacancy detected until prompt is displayed
/// </summary>
protected int RoomVacancyShutdownPromptSeconds;
/// <summary>
///
/// </summary>
protected abstract Func<bool> OnFeedbackFunc { get; }
protected Dictionary<IBasicVolumeWithFeedback, uint> SavedVolumeLevels = new Dictionary<IBasicVolumeWithFeedback, uint>();
/// <summary>
/// When volume control devices change, should we zero the one that we are leaving?
/// </summary>
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; }
public EssentialsRoomBase(DeviceConfig config)
: base(config)
{
// Setup the ShutdownPromptTimer
ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer");
ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) =>
{
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
ShutdownType = eShutdownType.None;
};
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
ShutdownPromptSeconds = 60;
ShutdownVacancySeconds = 120;
ShutdownType = eShutdownType.None;
RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer");
//RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) =>
//{
// if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue)
// ShutdownType = ShutdownType.Vacancy;
//};
RoomVacancyShutdownTimer.HasFinished += new EventHandler<EventArgs>(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered
RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning
RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt
VacancyMode = eVacancyMode.None;
OnFeedback = new BoolFeedback(OnFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc);
IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc);
AddPostActivationAction(() =>
{
if (RoomOccupancy != null)
OnRoomOccupancyIsSet();
});
}
void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
switch (VacancyMode)
{
case eVacancyMode.None:
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
break;
case eVacancyMode.InInitialVacancy:
StartRoomVacancyTimer(eVacancyMode.InShutdownWarning);
break;
case eVacancyMode.InShutdownWarning:
{
StartShutdown(eShutdownType.Vacancy);
Debug.Console(0, this, "Shutting Down due to vacancy.");
break;
}
default:
break;
}
}
/// <summary>
///
/// </summary>
/// <param name="type"></param>
public void StartShutdown(eShutdownType type)
{
// Check for shutdowns running. Manual should override other shutdowns
if (type == eShutdownType.Manual)
ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds;
else if (type == eShutdownType.Vacancy)
ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds;
ShutdownType = type;
ShutdownPromptTimer.Start();
Debug.Console(0, this, "ShutdwonPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount);
}
public void StartRoomVacancyTimer(eVacancyMode mode)
{
if (mode == eVacancyMode.None)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds;
else if (mode == eVacancyMode.InInitialVacancy)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds;
VacancyMode = mode;
RoomVacancyShutdownTimer.Start();
Debug.Console(0, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount);
}
/// <summary>
/// Resets the vacancy mode and shutsdwon the room
/// </summary>
public void Shutdown()
{
VacancyMode = eVacancyMode.None;
EndShutdown();
}
/// <summary>
/// This method is for the derived class to define it's specific shutdown
/// requirements but should not be called directly. It is called by Shutdown()
/// </summary>
protected abstract void EndShutdown();
/// <summary>
/// Override this to implement a default volume level(s) method
/// </summary>
public abstract void SetDefaultLevels();
/// <summary>
/// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device
/// </summary>
/// <param name="statusProvider"></param>
public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes)
{
if (statusProvider == null)
{
Debug.Console(0, this, "ERROR: Occupancy sensor device is null");
return;
}
// If status provider is fusion, set flag to remote
if (statusProvider is PepperDash.Essentials.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
OccupancyStatusProviderIsRemote = true;
if(timeoutMinutes > 0)
RoomVacancyShutdownSeconds = timeoutMinutes * 60;
Debug.Console(1, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds);
RoomOccupancy = statusProvider;
OnRoomOccupancyIsSet();
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
Debug.Console(0, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key);
}
void OnRoomOccupancyIsSet()
{
var handler = RoomOccupancyIsSet;
if (handler != null)
handler(this, new EventArgs());
}
/// <summary>
/// To allow base class to power room on to last source
/// </summary>
public abstract void PowerOnToDefaultOrLastSource();
/// <summary>
/// To allow base class to power room on to default source
/// </summary>
/// <returns></returns>
public abstract bool RunDefaultPresentRoute();
void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
{
Debug.Console(1, this, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
}
else
{
Debug.Console(1, this, "Notice: Occupancy Detected");
// Reset the timer when the room is occupied
RoomVacancyShutdownTimer.Cancel();
}
}
/// <summary>
/// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed
/// </summary>
/// <param name="o"></param>
public abstract void RoomVacatedForTimeoutPeriod(object o);
}
/// <summary>
/// To describe the various ways a room may be shutting down
/// </summary>
public enum eShutdownType
{
None = 0,
External,
Manual,
Vacancy
}
public enum eVacancyMode
{
None = 0,
InInitialVacancy,
InShutdownWarning
}
/// <summary>
///
/// </summary>
public enum eWarmingCoolingMode
{
None,
Warming,
Cooling
}
}

View File

@@ -1,108 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http;
using PepperDash.Core;
namespace PepperDash.Essentials
{
public class HttpLogoServer
{
/// <summary>
///
/// </summary>
HttpServer Server;
/// <summary>
///
/// </summary>
string FileDirectory;
/// <summary>
///
/// </summary>
public static Dictionary<string, string> ExtensionContentTypes;
/// <summary>
///
/// </summary>
/// <param name="port"></param>
/// <param name="directory"></param>
public HttpLogoServer(int port, string directory)
{
ExtensionContentTypes = new Dictionary<string, string>
{
//{ ".css", "text/css" },
//{ ".htm", "text/html" },
//{ ".html", "text/html" },
{ ".jpg", "image/jpeg" },
{ ".jpeg", "image/jpeg" },
//{ ".js", "application/javascript" },
//{ ".json", "application/json" },
//{ ".map", "application/x-navimap" },
{ ".pdf", "application.pdf" },
{ ".png", "image/png" },
//{ ".txt", "text/plain" },
};
Server = new HttpServer();
Server.Port = port;
FileDirectory = directory;
Server.OnHttpRequest += new OnHttpRequestHandler(Server_OnHttpRequest);
Server.Open();
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
}
/// <summary>
///
/// </summary>
void Server_OnHttpRequest(object sender, OnHttpRequestArgs args)
{
var path = args.Request.Path;
if (File.Exists(FileDirectory + @"\" + path))
{
string filePath = path.Replace('/', '\\');
string localPath = string.Format(@"{0}{1}", FileDirectory, filePath);
if (File.Exists(localPath))
{
args.Response.Header.ContentType = GetContentType(new FileInfo(localPath).Extension);
args.Response.ContentStream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
}
else
{
args.Response.ContentString = string.Format("Not found: '{0}'", filePath);
args.Response.Code = 404;
}
}
}
/// <summary>
///
/// </summary>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
Server.Close();
}
/// <summary>
///
/// </summary>
/// <param name="extension"></param>
/// <returns></returns>
public static string GetContentType(string extension)
{
string type;
if (ExtensionContentTypes.ContainsKey(extension))
type = ExtensionContentTypes[extension];
else
type = "text/plain";
return type;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
public class HttpLogoServer
{
/// <summary>
///
/// </summary>
HttpServer Server;
/// <summary>
///
/// </summary>
string FileDirectory;
/// <summary>
///
/// </summary>
public static Dictionary<string, string> ExtensionContentTypes;
/// <summary>
///
/// </summary>
/// <param name="port"></param>
/// <param name="directory"></param>
public HttpLogoServer(int port, string directory)
{
ExtensionContentTypes = new Dictionary<string, string>
{
//{ ".css", "text/css" },
//{ ".htm", "text/html" },
//{ ".html", "text/html" },
{ ".jpg", "image/jpeg" },
{ ".jpeg", "image/jpeg" },
//{ ".js", "application/javascript" },
//{ ".json", "application/json" },
//{ ".map", "application/x-navimap" },
{ ".pdf", "application.pdf" },
{ ".png", "image/png" },
//{ ".txt", "text/plain" },
};
Server = new HttpServer();
Server.Port = port;
FileDirectory = directory;
Server.OnHttpRequest += new OnHttpRequestHandler(Server_OnHttpRequest);
Server.Open();
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
}
/// <summary>
///
/// </summary>
void Server_OnHttpRequest(object sender, OnHttpRequestArgs args)
{
var path = args.Request.Path;
Debug.Console(2, "HTTP Request with path: '{0}'", args.Request.Path);
if (File.Exists(FileDirectory + path))
{
string filePath = path.Replace('/', '\\');
string localPath = string.Format(@"{0}{1}", FileDirectory, filePath);
Debug.Console(2, "HTTP Logo Server attempting to find file: '{0}'", localPath);
if (File.Exists(localPath))
{
args.Response.Header.ContentType = GetContentType(new FileInfo(localPath).Extension);
args.Response.ContentStream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
}
else
{
Debug.Console(2, "HTTP Logo Server Cannot find file '{0}'", localPath);
args.Response.ContentString = string.Format("Not found: '{0}'", filePath);
args.Response.Code = 404;
}
}
else
{
Debug.Console(2, "HTTP Logo Server: '{0}' does not exist", FileDirectory + path);
}
}
/// <summary>
///
/// </summary>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
Server.Close();
}
/// <summary>
///
/// </summary>
/// <param name="extension"></param>
/// <returns></returns>
public static string GetContentType(string extension)
{
string type;
if (ExtensionContentTypes.ContainsKey(extension))
type = ExtensionContentTypes[extension];
else
type = "text/plain";
return type;
}
}
}

View File

@@ -485,7 +485,31 @@ namespace PepperDash.Essentials
/// <summary>
/// 3955
/// </summary>
public const uint HeaderIcon5Press = 3955;
public const uint HeaderIcon5Press = 3955;
/// 3960
/// </summary>
public const uint HeaderPopupCaretsSubpageVisibile = 3960;
/// <summary>
/// 3961
/// </summary>
public const uint HeaderCaret1Visible = 3961;
/// <summary>
/// 3962
/// </summary>
public const uint HeaderCaret2Visible = 3962;
/// <summary>
/// 3963
/// </summary>
public const uint HeaderCaret3Visible = 3963;
/// <summary>
/// 3964
/// </summary>
public const uint HeaderCaret4Visible = 3964;
/// <summary>
/// 3965
/// </summary>
public const uint HeaderCaret5Visible = 3965;
/// <summary>
/// 3999

View File

@@ -1,251 +1,256 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Shades;
using PepperDash.Essentials.Core.Lighting;
namespace PepperDash.Essentials
{
public class EssentialsEnvironmentDriver : PanelDriverBase
{
/// <summary>
/// Do I need this here?
/// </summary>
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
/// The list of devices this driver is responsible for controlling
/// </summary>
public List<IKeyed> Devices { get; private set; }
/// <summary>
/// The parent driver for this
/// </summary>
EssentialsPanelMainInterfaceDriver Parent;
/// <summary>
/// The list of sub drivers for the devices
/// </summary>
public List<PanelDriverBase> DeviceSubDrivers { get; private set; }
public uint BackgroundSubpageJoin { get; private set; }
public EssentialsEnvironmentDriver(EssentialsPanelMainInterfaceDriver parent, CrestronTouchpanelPropertiesConfig config)
: base(parent.TriList)
{
Config = config;
Parent = parent;
Devices = new List<IKeyed>();
DeviceSubDrivers = new List<PanelDriverBase>();
Parent.AvDriver.PopupInterlock.IsShownFeedback.OutputChange += IsShownFeedback_OutputChange;
// Calculate the join offests for each device page and assign join actions for each button
}
void IsShownFeedback_OutputChange(object sender, EventArgs e)
{
// Hide this driver and all sub drivers if popup interlock is not shown
if (Parent.AvDriver.PopupInterlock.IsShownFeedback.BoolValue == false)
{
foreach (var driver in DeviceSubDrivers)
{
driver.Hide();
}
base.Hide();
}
}
/// <summary>
/// Shows this driver and all sub drivers
/// </summary>
public override void Show()
{
Parent.AvDriver.PopupInterlock.ShowInterlockedWithToggle(BackgroundSubpageJoin);
foreach (var driver in DeviceSubDrivers)
{
driver.Show();
}
base.Show();
}
/// <summary>
/// Hides this driver and all sub drivers
/// </summary>
public override void Hide()
{
Parent.AvDriver.PopupInterlock.HideAndClear();
foreach (var driver in DeviceSubDrivers)
{
driver.Hide();
}
base.Hide();
}
public override void Toggle()
{
if (IsVisible)
Hide();
else
Show();
}
/// <summary>
/// Reads the device keys from the config and gets the devices by key
/// </summary>
public void GetDevicesFromConfig(Room.Config.EssentialsEnvironmentPropertiesConfig EnvironmentPropertiesConfig)
{
if (EnvironmentPropertiesConfig != null)
{
Devices.Clear();
DeviceSubDrivers.Clear();
uint column = 1;
foreach (var dKey in EnvironmentPropertiesConfig.DeviceKeys)
{
var device = DeviceManager.GetDeviceForKey(dKey);
if (device != null)
{
// Build the driver
var devicePanelDriver = GetPanelDriverForDevice(device, column);
// Add new PanelDriverBase SubDriver
if (devicePanelDriver != null)
{
Devices.Add(device);
DeviceSubDrivers.Add(devicePanelDriver);
Debug.Console(1, "Adding '{0}' to Environment Devices", device.Key);
column++;
// Quit if device count is exceeded
if (column > 4)
break;
}
else
Debug.Console(1, "Unable to build environment driver for device: '{0}'", device.Key);
}
}
SetupEnvironmentUiJoins();
}
else
{
Debug.Console(1, "Unable to get devices from config. No EnvironmentPropertiesConfig object in room config");
}
}
/// <summary>
/// Returns the appropriate panel driver for the device
/// </summary>
/// <param name="device"></param>
/// <param name="column"></param>
/// <returns></returns>
PanelDriverBase GetPanelDriverForDevice(IKeyed device, uint column)
{
PanelDriverBase panelDriver = null;
uint buttonPressJoinBase = 0;
uint buttonVisibleJoinBase = 0;
uint stringJoinBase = 0;
uint shadeTypeVisibleBase = 0;
uint lightingTypeVisibleBase = 0;
switch (column)
{
case 1:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnOneButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnOneButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnOneLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnOneShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnOneLightingTypeVisibleBase;
break;
}
case 2:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnTwoButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnTwoButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnTwoLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnTwoShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnTwoLightingTypeVisibleBase;
break;
}
case 3:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnThreeButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnThreeButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnThreeLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnThreeShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnThreeLightingTypeVisibleBase;
break;
}
case 4:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnFourButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnFourButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnFourLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnFourShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnFourLightingTypeVisibleBase;
break;
}
default:
{
Debug.Console(1, "Environment Driver: Invalid column number specified");
break;
}
}
// Determine if device is a shade or lighting type and construct the appropriate driver
if (device is ShadeBase)
{
panelDriver = new EssentialsShadeDriver(this, device.Key, buttonPressJoinBase, stringJoinBase, shadeTypeVisibleBase);
}
else if (device is LightingBase)
{
panelDriver = new EssentialsLightingDriver(this, device.Key, buttonPressJoinBase, buttonVisibleJoinBase, stringJoinBase, lightingTypeVisibleBase);
}
// Return the driver
return panelDriver;
}
/// <summary>
/// Determines the join values for the generic environment subpages
/// </summary>
void SetupEnvironmentUiJoins()
{
// Calculate which background subpage join to use
BackgroundSubpageJoin = UIBoolJoin.EnvironmentBackgroundSubpageVisibleBase + (uint)DeviceSubDrivers.Count;
}
}
public interface IEnvironmentSubdriver
{
uint SubpageVisibleJoin { get; }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Shades;
using PepperDash.Essentials.Core.Lighting;
namespace PepperDash.Essentials
{
public class EssentialsEnvironmentDriver : PanelDriverBase
{
/// <summary>
/// Do I need this here?
/// </summary>
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
/// The list of devices this driver is responsible for controlling
/// </summary>
public List<IKeyed> Devices { get; private set; }
/// <summary>
/// The parent driver for this
/// </summary>
EssentialsPanelMainInterfaceDriver Parent;
/// <summary>
/// The list of sub drivers for the devices
/// </summary>
public List<PanelDriverBase> DeviceSubDrivers { get; private set; }
public uint BackgroundSubpageJoin { get; private set; }
public EssentialsEnvironmentDriver(EssentialsPanelMainInterfaceDriver parent, CrestronTouchpanelPropertiesConfig config)
: base(parent.TriList)
{
Config = config;
Parent = parent;
Devices = new List<IKeyed>();
DeviceSubDrivers = new List<PanelDriverBase>();
Parent.AvDriver.PopupInterlock.StatusChanged += new EventHandler<StatusChangedEventArgs>(PopupInterlock_CurrentJoinChanged);
// Calculate the join offests for each device page and assign join actions for each button
}
void PopupInterlock_CurrentJoinChanged(object sender, StatusChangedEventArgs e)
{
// Hide this driver and all sub drivers if popup interlock is not shown
if (!e.IsShown || e.NewJoin != BackgroundSubpageJoin)
{
foreach (var driver in DeviceSubDrivers)
{
driver.Hide();
}
base.Hide();
}
}
void IsShownFeedback_OutputChange(object sender, EventArgs e)
{
}
/// <summary>
/// Shows this driver and all sub drivers
/// </summary>
public override void Show()
{
Parent.AvDriver.PopupInterlock.ShowInterlocked(BackgroundSubpageJoin);
foreach (var driver in DeviceSubDrivers)
{
driver.Show();
}
base.Show();
}
/// <summary>
/// Hides this driver and all sub drivers
/// </summary>
public override void Hide()
{
Parent.AvDriver.PopupInterlock.HideAndClear();
foreach (var driver in DeviceSubDrivers)
{
driver.Hide();
}
base.Hide();
}
public override void Toggle()
{
if (IsVisible)
Hide();
else
Show();
}
/// <summary>
/// Reads the device keys from the config and gets the devices by key
/// </summary>
public void GetDevicesFromConfig(Room.Config.EssentialsEnvironmentPropertiesConfig EnvironmentPropertiesConfig)
{
if (EnvironmentPropertiesConfig != null)
{
Devices.Clear();
DeviceSubDrivers.Clear();
uint column = 1;
foreach (var dKey in EnvironmentPropertiesConfig.DeviceKeys)
{
var device = DeviceManager.GetDeviceForKey(dKey);
if (device != null)
{
// Build the driver
var devicePanelDriver = GetPanelDriverForDevice(device, column);
// Add new PanelDriverBase SubDriver
if (devicePanelDriver != null)
{
Devices.Add(device);
DeviceSubDrivers.Add(devicePanelDriver);
Debug.Console(1, "Adding '{0}' to Environment Devices", device.Key);
column++;
// Quit if device count is exceeded
if (column > 4)
break;
}
else
Debug.Console(1, "Unable to build environment driver for device: '{0}'", device.Key);
}
}
SetupEnvironmentUiJoins();
}
else
{
Debug.Console(1, "Unable to get devices from config. No EnvironmentPropertiesConfig object in room config");
}
}
/// <summary>
/// Returns the appropriate panel driver for the device
/// </summary>
/// <param name="device"></param>
/// <param name="column"></param>
/// <returns></returns>
PanelDriverBase GetPanelDriverForDevice(IKeyed device, uint column)
{
PanelDriverBase panelDriver = null;
uint buttonPressJoinBase = 0;
uint buttonVisibleJoinBase = 0;
uint stringJoinBase = 0;
uint shadeTypeVisibleBase = 0;
uint lightingTypeVisibleBase = 0;
switch (column)
{
case 1:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnOneButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnOneButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnOneLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnOneShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnOneLightingTypeVisibleBase;
break;
}
case 2:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnTwoButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnTwoButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnTwoLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnTwoShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnTwoLightingTypeVisibleBase;
break;
}
case 3:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnThreeButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnThreeButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnThreeLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnThreeShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnThreeLightingTypeVisibleBase;
break;
}
case 4:
{
buttonPressJoinBase = UIBoolJoin.EnvironmentColumnFourButtonPressBase;
buttonVisibleJoinBase = UIBoolJoin.EnvironmentColumnFourButtonVisibleBase;
stringJoinBase = UIStringJoin.EnvironmentColumnFourLabelBase;
shadeTypeVisibleBase = UIBoolJoin.EnvironmentColumnFourShadingTypeVisibleBase;
lightingTypeVisibleBase = UIBoolJoin.EnvironmentColumnFourLightingTypeVisibleBase;
break;
}
default:
{
Debug.Console(1, "Environment Driver: Invalid column number specified");
break;
}
}
// Determine if device is a shade or lighting type and construct the appropriate driver
if (device is ShadeBase)
{
panelDriver = new EssentialsShadeDriver(this, device.Key, buttonPressJoinBase, stringJoinBase, shadeTypeVisibleBase);
}
else if (device is LightingBase)
{
panelDriver = new EssentialsLightingDriver(this, device.Key, buttonPressJoinBase, buttonVisibleJoinBase, stringJoinBase, lightingTypeVisibleBase);
}
// Return the driver
return panelDriver;
}
/// <summary>
/// Determines the join values for the generic environment subpages
/// </summary>
void SetupEnvironmentUiJoins()
{
// Calculate which background subpage join to use
BackgroundSubpageJoin = UIBoolJoin.EnvironmentBackgroundSubpageVisibleBase + (uint)DeviceSubDrivers.Count;
}
}
public interface IEnvironmentSubdriver
{
uint SubpageVisibleJoin { get; }
}
}

View File

@@ -1,266 +1,371 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.UI;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public class EssentialsHeaderDriver : PanelDriverBase
{
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
/// The parent driver for this
/// </summary>
EssentialsPanelMainInterfaceDriver Parent;
/// <summary>
/// Indicates that the SetHeaderButtons method has completed successfully
/// </summary>
public bool HeaderButtonsAreSetUp { get; private set; }
StringInputSig HeaderCallButtonIconSig;
public EssentialsHeaderDriver(EssentialsPanelMainInterfaceDriver parent, CrestronTouchpanelPropertiesConfig config)
: base(parent.TriList)
{
Config = config;
Parent = parent;
}
void SetUpGear(IAVDriver avDriver, EssentialsRoomBase currentRoom)
{
// Gear
TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear");
TriList.SetSigHeldAction(UIBoolJoin.HeaderIcon5Press, 2000,
avDriver.ShowTech,
null,
() =>
{
if (currentRoom.OnFeedback.BoolValue)
avDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPageVisible);
else
avDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPagePowerOffVisible);
});
TriList.SetSigFalseAction(UIBoolJoin.TechExitButton, () =>
avDriver.PopupInterlock.HideAndClear());
}
void SetUpHelpButton(EssentialsRoomPropertiesConfig roomConf)
{
// Help roomConf and popup
if (roomConf.Help != null)
{
TriList.SetString(UIStringJoin.HelpMessage, roomConf.Help.Message);
TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, roomConf.Help.ShowCallButton);
TriList.SetString(UIStringJoin.HelpPageCallButtonText, roomConf.Help.CallButtonText);
if (roomConf.Help.ShowCallButton)
TriList.SetSigFalseAction(UIBoolJoin.HelpPageShowCallButtonPress, () => { }); // ************ FILL IN
else
TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress);
}
else // older config
{
TriList.SetString(UIStringJoin.HelpMessage, roomConf.HelpMessage);
TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, false);
TriList.SetString(UIStringJoin.HelpPageCallButtonText, null);
TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress);
}
TriList.SetString(UIStringJoin.HeaderButtonIcon4, "Help");
TriList.SetSigFalseAction(UIBoolJoin.HeaderIcon4Press, () =>
{
string message = null;
var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey)
as EssentialsHuddleSpaceRoom;
if (room != null)
message = room.Config.HelpMessage;
else
message = "Sorry, no help message available. No room connected.";
//TriList.StringInput[UIStringJoin.HelpMessage].StringValue = message;
Parent.AvDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HelpPageVisible);
});
}
uint SetUpEnvironmentButton(EssentialsEnvironmentDriver environmentDriver, uint nextJoin)
{
if (environmentDriver != null)
{
TriList.SetString(nextJoin, "Lights");
TriList.SetSigFalseAction(nextJoin, environmentDriver.Toggle);
nextJoin--;
return nextJoin;
}
else
return nextJoin;
}
uint SetUpCalendarButton(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, uint nextJoin)
{
// Calendar button
if (avDriver.CurrentRoom.ScheduleSource != null)
{
TriList.SetString(nextJoin, "Calendar");
TriList.SetSigFalseAction(nextJoin, avDriver.CalendarPress);
nextJoin--;
return nextJoin;
}
else
return nextJoin;
}
uint SetUpCallButton(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, uint nextJoin)
{
// Call button
TriList.SetString(nextJoin, "DND");
TriList.SetSigFalseAction(nextJoin, avDriver.ShowActiveCallsList);
HeaderCallButtonIconSig = TriList.StringInput[nextJoin];
nextJoin--;
return nextJoin;
}
/// <summary>
/// Evaluates the call status and sets the icon mode and text label
/// </summary>
public void ComputeHeaderCallStatus(VideoCodecBase codec)
{
if (codec == null)
{
Debug.Console(1, "ComputeHeaderCallStatus() cannot execute. codec is null");
return;
}
if (HeaderCallButtonIconSig == null)
{
Debug.Console(1, "ComputeHeaderCallStatus() cannot execute. HeaderCallButtonIconSig is null");
return;
}
// Set mode of header button
if (!codec.IsInCall)
{
HeaderCallButtonIconSig.StringValue = "DND";
//HeaderCallButton.SetIcon(HeaderListButton.OnHook);
}
else if (codec.ActiveCalls.Any(c => c.Type == eCodecCallType.Video))
HeaderCallButtonIconSig.StringValue = "Misc-06_Dark";
//HeaderCallButton.SetIcon(HeaderListButton.Camera);
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 2);
else
HeaderCallButtonIconSig.StringValue = "Misc-09_Dark";
//HeaderCallButton.SetIcon(HeaderListButton.Phone);
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 1);
// Set the call status text
if (codec.ActiveCalls.Count > 0)
{
if (codec.ActiveCalls.Count == 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "1 Active Call");
else if (codec.ActiveCalls.Count > 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, string.Format("{0} Active Calls", codec.ActiveCalls.Count));
}
else
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "No Active Calls");
}
/// <summary>
/// Sets up Header Buttons for the EssentialsHuddleVtc1Room type
/// </summary>
public void SetupHeaderButtons(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, EssentialsHuddleVtc1Room currentRoom)
{
HeaderButtonsAreSetUp = false;
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
var roomConf = currentRoom.Config;
SetUpGear(avDriver, currentRoom);
SetUpHelpButton(roomConf);
uint nextJoin = 3953;
nextJoin = SetUpEnvironmentButton(Parent.EnvironmentDriver, nextJoin);
nextJoin = SetUpCalendarButton(avDriver, nextJoin);
nextJoin = SetUpCallButton(avDriver, nextJoin);
// blank any that remain
for (var i = nextJoin; i > 3950; i--)
{
TriList.SetString(i, "Blank");
TriList.SetSigFalseAction(i, () => { });
}
TriList.SetSigFalseAction(UIBoolJoin.HeaderCallStatusLabelPress, avDriver.ShowActiveCallsList);
// Set Call Status Subpage Position
if (nextJoin == 3951)
{
// Set to right position
TriList.SetBool(UIBoolJoin.HeaderCallStatusLeftPositionVisible, false);
TriList.SetBool(UIBoolJoin.HeaderCallStatusRightPositionVisible, true);
}
else if (nextJoin == 3950)
{
// Set to left position
TriList.SetBool(UIBoolJoin.HeaderCallStatusLeftPositionVisible, true);
TriList.SetBool(UIBoolJoin.HeaderCallStatusRightPositionVisible, false);
}
HeaderButtonsAreSetUp = true;
ComputeHeaderCallStatus(currentRoom.VideoCodec);
}
/// <summary>
/// Sets up Header Buttons for the EssentialsHuddleSpaceRoom type
/// </summary>
public void SetupHeaderButtons(EssentialsHuddlePanelAvFunctionsDriver avDriver, EssentialsHuddleSpaceRoom currentRoom)
{
HeaderButtonsAreSetUp = false;
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
var roomConf = currentRoom.Config;
SetUpGear(avDriver, currentRoom);
SetUpHelpButton(roomConf);
uint nextJoin = 3953;
nextJoin = SetUpEnvironmentButton(Parent.EnvironmentDriver, nextJoin);
// blank any that remain
for (var i = nextJoin; i > 3950; i--)
{
TriList.SetString(i, "Blank");
TriList.SetSigFalseAction(i, () => { });
}
HeaderButtonsAreSetUp = true;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.UI;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public class EssentialsHeaderDriver : PanelDriverBase
{
uint EnvironmentCaretVisible;
uint CalendarCaretVisible;
uint CallCaretVisible;
JoinedSigInterlock CaretInterlock;
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
/// The parent driver for this
/// </summary>
EssentialsPanelMainInterfaceDriver Parent;
/// <summary>
/// Indicates that the SetHeaderButtons method has completed successfully
/// </summary>
public bool HeaderButtonsAreSetUp { get; private set; }
StringInputSig HeaderCallButtonIconSig;
public EssentialsHeaderDriver(EssentialsPanelMainInterfaceDriver parent, CrestronTouchpanelPropertiesConfig config)
: base(parent.TriList)
{
Config = config;
Parent = parent;
CaretInterlock = new JoinedSigInterlock(TriList);
}
void SetUpGear(IAVDriver avDriver, EssentialsRoomBase currentRoom)
{
// Gear
TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear");
TriList.SetSigHeldAction(UIBoolJoin.HeaderIcon5Press, 2000,
avDriver.ShowTech,
null,
() =>
{
if (currentRoom.OnFeedback.BoolValue)
{
avDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPageVisible);
CaretInterlock.ShowInterlocked(UIBoolJoin.HeaderCaret5Visible);
}
else
{
avDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPagePowerOffVisible);
CaretInterlock.ShowInterlocked(UIBoolJoin.HeaderCaret5Visible);
}
});
TriList.SetSigFalseAction(UIBoolJoin.TechExitButton, () =>
avDriver.PopupInterlock.HideAndClear());
}
public void SetUpHelpButton(EssentialsRoomPropertiesConfig roomConf)
{
// Help roomConf and popup
if (roomConf.Help != null)
{
TriList.SetString(UIStringJoin.HelpMessage, roomConf.Help.Message);
TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, roomConf.Help.ShowCallButton);
TriList.SetString(UIStringJoin.HelpPageCallButtonText, roomConf.Help.CallButtonText);
if (roomConf.Help.ShowCallButton)
{
TriList.SetSigFalseAction(UIBoolJoin.HelpPageShowCallButtonPress, () => { }); // ************ FILL IN
}
else
{
TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress);
}
}
else // older config
{
TriList.SetString(UIStringJoin.HelpMessage, roomConf.HelpMessage);
TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, false);
TriList.SetString(UIStringJoin.HelpPageCallButtonText, null);
TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress);
}
TriList.SetString(UIStringJoin.HeaderButtonIcon4, "Help");
TriList.SetSigFalseAction(UIBoolJoin.HeaderIcon4Press, () =>
{
string message = null;
var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey)
as EssentialsHuddleSpaceRoom;
if (room != null)
message = room.PropertiesConfig.HelpMessage;
else
message = "Sorry, no help message available. No room connected.";
//TriList.StringInput[UIStringJoin.HelpMessage].StringValue = message;
Parent.AvDriver.PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HelpPageVisible);
CaretInterlock.ShowInterlocked(UIBoolJoin.HeaderCaret4Visible);
});
}
uint SetUpEnvironmentButton(EssentialsEnvironmentDriver environmentDriver, uint nextJoin)
{
if (environmentDriver != null)
{
var tempJoin = nextJoin;
TriList.SetString(tempJoin, "Lights");
EnvironmentCaretVisible = tempJoin + 10;
TriList.SetSigFalseAction(tempJoin, () =>
{
environmentDriver.Toggle();
CaretInterlock.ShowInterlocked(EnvironmentCaretVisible);
});
nextJoin--;
return nextJoin;
}
else
return nextJoin;
}
uint SetUpCalendarButton(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, uint nextJoin)
{
// Calendar button
if (avDriver.CurrentRoom.ScheduleSource != null)
{
var tempJoin = nextJoin;
TriList.SetString(tempJoin, "Calendar");
CalendarCaretVisible = tempJoin + 10;
TriList.SetSigFalseAction(tempJoin, () =>
{
avDriver.CalendarPress();
CaretInterlock.ShowInterlocked(CalendarCaretVisible);
});
nextJoin--;
return nextJoin;
}
else
return nextJoin;
}
uint SetUpCallButton(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, uint nextJoin)
{
// Call button
var tempJoin = nextJoin;
TriList.SetString(tempJoin, "DND");
CallCaretVisible = tempJoin + 10;
TriList.SetSigFalseAction(tempJoin, () =>
{
avDriver.ShowActiveCallsList();
if(avDriver.CurrentRoom.InCallFeedback.BoolValue)
CaretInterlock.ShowInterlocked(CallCaretVisible);
});
HeaderCallButtonIconSig = TriList.StringInput[tempJoin];
nextJoin--;
return nextJoin;
}
/// <summary>
/// Evaluates the call status and sets the icon mode and text label
/// </summary>
public void ComputeHeaderCallStatus(VideoCodecBase codec)
{
if (codec == null)
{
Debug.Console(1, "ComputeHeaderCallStatus() cannot execute. codec is null");
return;
}
if (HeaderCallButtonIconSig == null)
{
Debug.Console(1, "ComputeHeaderCallStatus() cannot execute. HeaderCallButtonIconSig is null");
return;
}
// Set mode of header button
if (!codec.IsInCall)
{
HeaderCallButtonIconSig.StringValue = "DND";
//HeaderCallButton.SetIcon(HeaderListButton.OnHook);
}
else if (codec.ActiveCalls.Any(c => c.Type == eCodecCallType.Video))
HeaderCallButtonIconSig.StringValue = "Misc-06_Dark";
//HeaderCallButton.SetIcon(HeaderListButton.Camera);
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 2);
else
HeaderCallButtonIconSig.StringValue = "Misc-09_Dark";
//HeaderCallButton.SetIcon(HeaderListButton.Phone);
//TriList.SetUshort(UIUshortJoin.CallHeaderButtonMode, 1);
// Set the call status text
if (codec.ActiveCalls.Count > 0)
{
if (codec.ActiveCalls.Count == 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "1 Active Call");
else if (codec.ActiveCalls.Count > 1)
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, string.Format("{0} Active Calls", codec.ActiveCalls.Count));
}
else
TriList.SetString(UIStringJoin.HeaderCallStatusLabel, "No Active Calls");
}
/// <summary>
/// Sets up Header Buttons for the EssentialsHuddleVtc1Room type
/// </summary>
public void SetupHeaderButtons(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, EssentialsHuddleVtc1Room currentRoom)
{
HeaderButtonsAreSetUp = false;
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
var roomConf = currentRoom.PropertiesConfig;
// Register for the PopupInterlock IsShowsFeedback event to tie the header carets subpage visiblity to it
Parent.AvDriver.PopupInterlock.StatusChanged -= PopupInterlock_StatusChanged;
Parent.AvDriver.PopupInterlock.StatusChanged += PopupInterlock_StatusChanged;
SetUpGear(avDriver, currentRoom);
SetUpHelpButton(roomConf);
uint nextJoin = 3953;
nextJoin = SetUpEnvironmentButton(Parent.EnvironmentDriver, nextJoin);
nextJoin = SetUpCalendarButton(avDriver, nextJoin);
nextJoin = SetUpCallButton(avDriver, nextJoin);
// blank any that remain
for (var i = nextJoin; i > 3950; i--)
{
TriList.SetString(i, "Blank");
TriList.SetSigFalseAction(i, () => { });
}
TriList.SetSigFalseAction(UIBoolJoin.HeaderCallStatusLabelPress,
() =>
{
avDriver.ShowActiveCallsList();
if (avDriver.CurrentRoom.InCallFeedback.BoolValue)
CaretInterlock.ShowInterlocked(CallCaretVisible);
});
// Set Call Status Subpage Position
if (nextJoin == 3951)
{
// Set to right position
TriList.SetBool(UIBoolJoin.HeaderCallStatusLeftPositionVisible, false);
TriList.SetBool(UIBoolJoin.HeaderCallStatusRightPositionVisible, true);
}
else if (nextJoin == 3950)
{
// Set to left position
TriList.SetBool(UIBoolJoin.HeaderCallStatusLeftPositionVisible, true);
TriList.SetBool(UIBoolJoin.HeaderCallStatusRightPositionVisible, false);
}
HeaderButtonsAreSetUp = true;
ComputeHeaderCallStatus(currentRoom.VideoCodec);
}
/// <summary>
/// Sets up Header Buttons for the EssentialsHuddleSpaceRoom type
/// </summary>
public void SetupHeaderButtons(EssentialsHuddlePanelAvFunctionsDriver avDriver, EssentialsHuddleSpaceRoom currentRoom)
{
HeaderButtonsAreSetUp = false;
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
var roomConf = currentRoom.PropertiesConfig;
// Register for the PopupInterlock IsShowsFeedback event to tie the header carets subpage visiblity to it
Parent.AvDriver.PopupInterlock.StatusChanged -= PopupInterlock_StatusChanged;
Parent.AvDriver.PopupInterlock.StatusChanged += PopupInterlock_StatusChanged;
SetUpGear(avDriver, currentRoom);
SetUpHelpButton(roomConf);
uint nextJoin = 3953;
nextJoin = SetUpEnvironmentButton(Parent.EnvironmentDriver, nextJoin);
// blank any that remain
for (var i = nextJoin; i > 3950; i--)
{
TriList.SetString(i, "Blank");
TriList.SetSigFalseAction(i, () => { });
}
HeaderButtonsAreSetUp = true;
}
///// <summary>
///// Whenever a popup is shown/hidden, show/hide the header carets subpage and set the visibility of the correct caret
///// </summary>
///// <param name="sender"></param>
///// <param name="e"></param>
//void IsShownFeedback_OutputChange(object sender, EventArgs e)
//{
// var popupInterlockIsShown = Parent.AvDriver.PopupInterlock.IsShown;
// // Set the visible state for the HeaderPopupCaretsSubpage to match that of the PopupInterlock state
// TriList.SetBool(UIBoolJoin.HeaderPopupCaretsSubpageVisibile, popupInterlockIsShown);
// // Clear all caret visibility
// for (uint i = UIBoolJoin.HeaderCaret5Visible; i >= UIBoolJoin.HeaderCaret1Visible; i--)
// {
// TriList.SetBool(i, false);
// }
// // Set the current caret visible if the popup is still shown
// if (popupInterlockIsShown)
// TriList.SetBool(NextCaretVisible, true);
//}
/// <summary>
/// Whenever a popup is shown/hidden, show/hide the header carets subpage and set the visibility of the correct caret
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void PopupInterlock_StatusChanged(object sender, StatusChangedEventArgs e)
{
// Set the visible state for the HeaderPopupCaretsSubpage to match that of the PopupInterlock state
bool headerPopupShown = false;
// Check if the popup interlock is shown, and if one of the header popups is current, then show the carets subpage
if (e.IsShown)
{
if (e.NewJoin == Parent.EnvironmentDriver.BackgroundSubpageJoin)
headerPopupShown = true;
else if (e.NewJoin == UIBoolJoin.HeaderActiveCallsListVisible)
headerPopupShown = true;
else if (e.NewJoin == UIBoolJoin.HelpPageVisible)
headerPopupShown = true;
else if (e.NewJoin == UIBoolJoin.MeetingsOrContacMethodsListVisible)
headerPopupShown = true;
else if (e.NewJoin == UIBoolJoin.VolumesPagePowerOffVisible || e.NewJoin == UIBoolJoin.VolumesPageVisible)
headerPopupShown = true;
}
// Set the carets subpage visibility
TriList.SetBool(UIBoolJoin.HeaderPopupCaretsSubpageVisibile, headerPopupShown);
if (!e.IsShown)
CaretInterlock.HideAndClear();
}
}
}

View File

@@ -6,6 +6,7 @@ using Crestron.SimplSharpPro.UI;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.PageManagers;
@@ -163,7 +164,7 @@ namespace PepperDash.Essentials
get
{
if (_TechDriver == null)
_TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.Config.Tech);
_TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.PropertiesConfig.Tech);
return _TechDriver;
}
}
@@ -219,9 +220,7 @@ namespace PepperDash.Essentials
return;
}
var roomConf = CurrentRoom.Config;
TriList.SetString(UIStringJoin.CurrentRoomName, CurrentRoom.Name);
var roomConf = CurrentRoom.PropertiesConfig;
if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero)
{
@@ -480,7 +479,7 @@ namespace PepperDash.Essentials
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true;
// Run default source when room is off and share is pressed
if (!CurrentRoom.OnFeedback.BoolValue)
CurrentRoom.RunDefaultRoute();
CurrentRoom.RunDefaultPresentRoute();
}
@@ -592,7 +591,7 @@ namespace PepperDash.Essentials
EndMeetingButtonSig.BoolValue = true;
ShareButtonSig.BoolValue = false;
if (CurrentRoom.ShutdownType == eShutdownType.Manual)
if (CurrentRoom.ShutdownType == eShutdownType.Manual || CurrentRoom.ShutdownType == eShutdownType.Vacancy)
{
PowerDownModal = new ModalDialog(TriList);
var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds);
@@ -723,63 +722,62 @@ namespace PepperDash.Essentials
CurrentRoom.CurrentVolumeControls.VolumeDown(state);
}
/// <summary>
/// Helper for property setter. Sets the panel to the given room, latching up all functionality
/// </summary>
void SetCurrentRoom(EssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
if (_CurrentRoom != null)
{
// Disconnect current room
_CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange;
ClearAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange;
DisconnectSource(_CurrentRoom.CurrentSourceInfo);
/// <summary>
/// Helper for property setter. Sets the panel to the given room, latching up all functionality
/// </summary>
public void RefreshCurrentRoom(EssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom != null)
{
// Disconnect current room
_CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange;
ClearAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange;
DisconnectSource(_CurrentRoom.CurrentSourceInfo);
_CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted;
_CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished;
_CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled;
_CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange;
_CurrentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange;
_CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange;
_CurrentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange;
}
_CurrentRoom = room;
_CurrentRoom = room;
if (_CurrentRoom != null)
{
// get the source list config and set up the source list
var config = ConfigReader.ConfigObject.SourceLists;
if (config.ContainsKey(_CurrentRoom.SourceListKey))
{
var srcList = config[_CurrentRoom.SourceListKey];
// Setup sources list
uint i = 1; // counter for UI list
foreach (var kvp in srcList)
{
var srcConfig = kvp.Value;
if (!srcConfig.IncludeInSourceList) // Skip sources marked this way
continue;
if (_CurrentRoom != null)
{
// get the source list config and set up the source list
var config = ConfigReader.ConfigObject.SourceLists;
if (config.ContainsKey(_CurrentRoom.SourceListKey))
{
var srcList = config[_CurrentRoom.SourceListKey];
// Setup sources list
uint i = 1; // counter for UI list
foreach (var kvp in srcList)
{
var srcConfig = kvp.Value;
if (!srcConfig.IncludeInSourceList) // Skip sources marked this way
continue;
var actualSource = DeviceManager.GetDeviceForKey(srcConfig.SourceKey) as Device;
if (actualSource == null)
{
Debug.Console(1, "Cannot assign missing source '{0}' to source UI list",
srcConfig.SourceKey);
continue;
}
var routeKey = kvp.Key;
var actualSource = DeviceManager.GetDeviceForKey(srcConfig.SourceKey) as Device;
if (actualSource == null)
{
Debug.Console(1, "Cannot assign missing source '{0}' to source UI list",
srcConfig.SourceKey);
continue;
}
var routeKey = kvp.Key;
var item = new SubpageReferenceListSourceItem(i++, SourcesSrl, srcConfig,
b => { if (!b) UiSelectSource(routeKey); });
SourcesSrl.AddItem(item); // add to the SRL
item.RegisterForSourceChange(_CurrentRoom);
}
}
SourcesSrl.Count = (ushort)(i - 1);
}
}
// Name and logo
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name;
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name;
if (_CurrentRoom.LogoUrl == null)
{
TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = true;
@@ -803,97 +801,40 @@ namespace PepperDash.Essentials
_CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange;
_CurrentRoom.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
_CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
RefreshAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange;
RefreshSourceInfo();
_CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
RefreshAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange;
RefreshSourceInfo();
(Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom);
}
else
{
// Clear sigs that need to be
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room";
}
else
{
// Clear sigs that need to be
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room";
}
}
void SetCurrentRoom(EssentialsHuddleSpaceRoom room)
{
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
room.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged += room_ConfigChanged;
RefreshCurrentRoom(room);
}
//void SetupHeaderButtons()
//{
// HeaderButtonsAreSetUp = false;
// TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true);
// var roomConf = CurrentRoom.Config;
// // Gear
// TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear");
// TriList.SetSigHeldAction(UIBoolJoin.HeaderIcon5Press, 2000,
// ShowTech,
// null,
// () =>
// {
// if (CurrentRoom.OnFeedback.BoolValue)
// PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPageVisible);
// else
// PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPagePowerOffVisible);
// });
// TriList.SetSigFalseAction(UIBoolJoin.TechExitButton, () =>
// PopupInterlock.HideAndClear());
// // Help button and popup
// if (CurrentRoom.Config.Help != null)
// {
// TriList.SetString(UIStringJoin.HelpMessage, roomConf.Help.Message);
// TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, roomConf.Help.ShowCallButton);
// TriList.SetString(UIStringJoin.HelpPageCallButtonText, roomConf.Help.CallButtonText);
// if (roomConf.Help.ShowCallButton)
// TriList.SetSigFalseAction(UIBoolJoin.HelpPageShowCallButtonPress, () => { }); // ************ FILL IN
// else
// TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress);
// }
// else // older config
// {
// TriList.SetString(UIStringJoin.HelpMessage, CurrentRoom.Config.HelpMessage);
// TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, false);
// TriList.SetString(UIStringJoin.HelpPageCallButtonText, null);
// TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress);
// }
// TriList.SetString(UIStringJoin.HeaderButtonIcon4, "Help");
// TriList.SetSigFalseAction(UIBoolJoin.HeaderIcon4Press, () =>
// {
// string message = null;
// var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey)
// as EssentialsHuddleSpaceRoom;
// if (room != null)
// message = room.Config.HelpMessage;
// else
// message = "Sorry, no help message available. No room connected.";
// //TriList.StringInput[UIStringJoin.HelpMessage].StringValue = message;
// PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HelpPageVisible);
// });
// uint nextJoin = 3953;
// //// Calendar button
// //if (_CurrentRoom.ScheduleSource != null)
// //{
// // TriList.SetString(nextJoin, "Calendar");
// // TriList.SetSigFalseAction(nextJoin, CalendarPress);
// // nextJoin--;
// //}
// //nextJoin--;
// // blank any that remain
// for (var i = nextJoin; i > 3950; i--)
// {
// TriList.SetString(i, "Blank");
// TriList.SetSigFalseAction(i, () => { });
// }
// HeaderButtonsAreSetUp = true;
//}
/// <summary>
/// Fires when room config of current room has changed. Meant to refresh room values to propegate any updates to UI
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void room_ConfigChanged(object sender, EventArgs e)
{
RefreshCurrentRoom(_CurrentRoom);
}
/// <summary>
/// For room on/off changes

View File

@@ -8,7 +8,8 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.SmartObjects;
using PepperDash.Essentials.Core.Touchpanels.Keyboards;
using PepperDash.Essentials.Devices.Displays;

View File

@@ -1,129 +1,175 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
public class JoinedSigInterlock
{
public uint CurrentJoin { get; private set; }
BasicTriList TriList;
public BoolFeedback IsShownFeedback;
bool _IsShown;
public bool IsShown
{
get
{
return _IsShown;
}
private set
{
_IsShown = value;
IsShownFeedback.FireUpdate();
}
}
//public BoolFeedback ShownFeedback { get; private set; }
public JoinedSigInterlock(BasicTriList triList)
{
TriList = triList;
IsShownFeedback = new BoolFeedback(new Func<bool>( () => _IsShown));
}
/// <summary>
/// Hides CurrentJoin and shows join. Will check and re-set signal if join
/// equals CurrentJoin
/// </summary>
public void ShowInterlocked(uint join)
{
Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
if (CurrentJoin == join && TriList.BooleanInput[join].BoolValue)
return;
SetButDontShow(join);
TriList.SetBool(CurrentJoin, true);
IsShown = true;
}
/// <summary>
///
/// </summary>
/// <param name="join"></param>
public void ShowInterlockedWithToggle(uint join)
{
Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
if (CurrentJoin == join)
HideAndClear();
else
{
if (CurrentJoin > 0)
TriList.BooleanInput[CurrentJoin].BoolValue = false;
CurrentJoin = join;
TriList.BooleanInput[CurrentJoin].BoolValue = true;
IsShown = true;
}
}
/// <summary>
/// Hides current join and clears CurrentJoin
/// </summary>
public void HideAndClear()
{
Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
Hide();
CurrentJoin = 0;
}
/// <summary>
/// Hides the current join but does not clear the selected join in case
/// it needs to be reshown
/// </summary>
public void Hide()
{
Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = false;
IsShown = false;
}
}
/// <summary>
/// If CurrentJoin is set, it restores that join
/// </summary>
public void Show()
{
Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin);
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = true;
IsShown = true;
}
}
/// <summary>
/// Useful for pre-setting the interlock but not enabling it. Sets CurrentJoin
/// </summary>
/// <param name="join"></param>
public void SetButDontShow(uint join)
{
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = false;
IsShown = false;
}
CurrentJoin = join;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
public class JoinedSigInterlock
{
public uint CurrentJoin { get; private set; }
BasicTriList TriList;
public BoolFeedback IsShownFeedback;
public event EventHandler<StatusChangedEventArgs> StatusChanged;
bool _IsShown;
public bool IsShown
{
get
{
return _IsShown;
}
private set
{
_IsShown = value;
IsShownFeedback.FireUpdate();
}
}
//public BoolFeedback ShownFeedback { get; private set; }
public JoinedSigInterlock(BasicTriList triList)
{
TriList = triList;
IsShownFeedback = new BoolFeedback(new Func<bool>( () => _IsShown));
}
/// <summary>
/// Hides CurrentJoin and shows join. Will check and re-set signal if join
/// equals CurrentJoin
/// </summary>
public void ShowInterlocked(uint join)
{
var prevJoin = CurrentJoin;
var wasShown = _IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
if (CurrentJoin == join && TriList.BooleanInput[join].BoolValue)
return;
SetButDontShow(join);
TriList.SetBool(CurrentJoin, true);
IsShown = true;
OnStatusChange(prevJoin, CurrentJoin, wasShown, IsShown);
}
/// <summary>
///
/// </summary>
/// <param name="join"></param>
public void ShowInterlockedWithToggle(uint join)
{
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock swapping {1} for {2}", TriList.ID, CurrentJoin, join);
if (CurrentJoin == join)
HideAndClear();
else
{
if (CurrentJoin > 0)
TriList.BooleanInput[CurrentJoin].BoolValue = false;
CurrentJoin = join;
TriList.BooleanInput[CurrentJoin].BoolValue = true;
IsShown = true;
OnStatusChange(prevJoin, CurrentJoin, wasShown, IsShown);
}
}
/// <summary>
/// Hides current join and clears CurrentJoin
/// </summary>
public void HideAndClear()
{
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
Hide();
CurrentJoin = 0;
OnStatusChange(prevJoin, CurrentJoin, wasShown, IsShown);
}
/// <summary>
/// Hides the current join but does not clear the selected join in case
/// it needs to be reshown
/// </summary>
public void Hide()
{
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock hiding {1}", TriList.ID, CurrentJoin);
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = false;
IsShown = false;
OnStatusChange(prevJoin, CurrentJoin, wasShown, IsShown);
}
}
/// <summary>
/// If CurrentJoin is set, it restores that join
/// </summary>
public void Show()
{
var prevJoin = CurrentJoin;
var wasShown = IsShown;
Debug.Console(2, "Trilist {0:X2}, interlock showing {1}", TriList.ID, CurrentJoin);
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = true;
IsShown = true;
OnStatusChange(prevJoin, CurrentJoin, wasShown, IsShown);
}
}
/// <summary>
/// Useful for pre-setting the interlock but not enabling it. Sets CurrentJoin
/// </summary>
/// <param name="join"></param>
public void SetButDontShow(uint join)
{
if (CurrentJoin > 0)
{
TriList.BooleanInput[CurrentJoin].BoolValue = false;
IsShown = false;
}
CurrentJoin = join;
}
void OnStatusChange(uint prevJoin, uint newJoin, bool wasShown, bool isShown)
{
var handler = StatusChanged;
if (handler != null)
handler(this, new StatusChangedEventArgs(prevJoin, newJoin, wasShown, isShown));
}
}
public class StatusChangedEventArgs : EventArgs
{
public uint PreviousJoin { get; set; }
public uint NewJoin { get; set; }
public bool WasShown { get; set; }
public bool IsShown { get; set; }
public StatusChangedEventArgs(uint prevJoin, uint newJoin, bool wasShown, bool isShown)
{
PreviousJoin = prevJoin;
NewJoin = newJoin;
WasShown = wasShown;
IsShown = isShown;
}
}
}

View File

@@ -0,0 +1,16 @@
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>
/// The handler type for a Room's SourceInfoChange
/// </summary>
public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type);
}

View File

@@ -202,8 +202,6 @@ namespace PepperDash.Essentials.UIDrivers.VC
{
string roomNumberSipUri = "";
#warning FIX PHONE FORMATTING TO ONLY SHOW WHEN APPROPRIATE - TALK TO NEIL
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
@@ -486,9 +484,9 @@ namespace PepperDash.Essentials.UIDrivers.VC
TriList.SetString(timeTextOffset + i, timeText);
string iconName = null;
if (c.OccurenceType == eCodecOccurrenceType.Received)
if (c.OccurrenceType == eCodecOccurrenceType.Received)
iconName = "Misc-18_Light";
else if (c.OccurenceType == eCodecOccurrenceType.Placed)
else if (c.OccurrenceType == eCodecOccurrenceType.Placed)
iconName = "Misc-17_Light";
else
iconName = "Delete";
@@ -539,25 +537,22 @@ namespace PepperDash.Essentials.UIDrivers.VC
var codec = Codec as IHasDirectory;
if (codec != null)
{
if (codec != null)
DirectoryList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCDirectoryList],
true, 1300);
codec.DirectoryResultReturned += new EventHandler<DirectoryEventArgs>(dir_DirectoryResultReturned);
if (codec.PhonebookSyncState.InitialSyncComplete)
SetCurrentDirectoryToRoot();
else
{
DirectoryList = new SmartObjectDynamicList(TriList.SmartObjects[UISmartObjectJoin.VCDirectoryList],
true, 1300);
codec.DirectoryResultReturned += new EventHandler<DirectoryEventArgs>(dir_DirectoryResultReturned);
if (codec.PhonebookSyncState.InitialSyncComplete)
SetCurrentDirectoryToRoot();
else
{
codec.PhonebookSyncState.InitialSyncCompleted += new EventHandler<EventArgs>(PhonebookSyncState_InitialSyncCompleted);
}
codec.PhonebookSyncState.InitialSyncCompleted += new EventHandler<EventArgs>(PhonebookSyncState_InitialSyncCompleted);
}
// If there is something here now, show it otherwise wait for the event
if (CurrentDirectoryResult != null && codec.DirectoryRoot.DirectoryResults.Count > 0)
{
RefreshDirectory();
}
// If there is something here now, show it otherwise wait for the event
if (CurrentDirectoryResult != null && codec.DirectoryRoot.DirectoryResults.Count > 0)
{
RefreshDirectory();
}
}
}

View File

@@ -1,41 +0,0 @@
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>
///
/// </summary>
public class VolumeDeviceChangeEventArgs : EventArgs
{
public IBasicVolumeControls OldDev { get; private set; }
public IBasicVolumeControls NewDev { get; private set; }
public ChangeType Type { get; private set; }
public VolumeDeviceChangeEventArgs(IBasicVolumeControls oldDev, IBasicVolumeControls newDev, ChangeType type)
{
OldDev = oldDev;
NewDev = newDev;
Type = type;
}
}
/// <summary>
/// The handler type for a Room's SourceInfoChange
/// </summary>
public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type);
/// <summary>
///
/// </summary>
public enum ChangeType
{
WillChange, DidChange
}
}

View File

@@ -29,3 +29,5 @@ devjson:1 {"deviceKey":"microphonePrivacyController-1", "methodName":"TogglePriv
devjson:1 {"deviceKey":"room1.InCallFeedback","methodName":"SetTestValue", "params": [ true ]}
devjson:1 {"deviceKey":"room1.InCallFeedback","methodName":"ClearTestValue", "params": []}
devjson:3 {"deviceKey":"room1.RoomOccupancy.RoomIsOccupiedFeedback","methodName":"SetTestValue", "params": [ true ]}