Compare commits

...

509 Commits

Author SHA1 Message Date
Andrew Welker
bbc994afb4 Merge branch 'development' into feature/mobile-control-interfaces 2024-10-31 09:55:02 -05:00
Andrew Welker
e7d7b8638e Merge pull request #1195 from PepperDash/feature/video-wall-mode
Feature/video wall mode
2024-07-12 09:20:25 -04:00
Colin Denig
0eb2436fa0 fix: videowall mode raw fb for dm-rmc-4kz-scaler-c 2024-07-11 15:42:25 -04:00
Colin Denig
192991cc65 fix(wip): DmRmc4kzScalerC VideoWallModeFb not working
- reverted PepperDashCode ref for Essentials_DM to unversioned and latest release
- fixed Scaler_OutputChange function params
- added instantiation of VideoWallModeRawFeedback
- feedback event trigger causing null ref exception
TODO:
-[] trace nullref exception cause
-[] Link Fb to Api
2024-07-10 16:45:02 -04:00
mhengeli
421f87db5e feat: add video wall mode command to dm-rmc-4kz-scaler-c 2024-07-09 20:06:49 -04:00
mhengeli
eb388d28db feat: add scaler mode for videowall set rmc 4kz scaler c 2024-06-21 15:37:28 -04:00
Neil Dorin
a2b7a39082 Merge pull request #1188 from PepperDash/hotfix/add-hdcp-control-to-airmedia
Hotfix/add hdcp control to airmedia
2024-05-16 15:31:35 -06:00
Jason T Alborough
78e49871c6 Merge branch 'main' into hotfix/add-hdcp-control-to-airmedia 2024-05-16 12:18:08 -04:00
Andrew Welker
12e81af9e6 Merge pull request #1183 from PepperDash/hotfix/bridge-warning-fix
Hotfix/bridge warning fix
2024-05-16 00:38:44 -05:00
Neil Dorin
544a7a2d73 Merge branch 'main' into hotfix/bridge-warning-fix 2024-05-02 09:46:45 -06:00
Neil Dorin
1d843c6c89 Merge pull request #1184 from PepperDash/hotfix/fix-ghidra-specific-verbiage
fix: ghidra specific verbiage
2024-05-02 09:46:23 -06:00
Neil Dorin
c72db72e7e Merge branch 'main' into feature/bridge-warning-fix 2024-04-26 09:58:02 -06:00
AECohn
9e588f4da5 fix: ghidra specific verbiage 2024-04-25 10:42:40 -04:00
Aviv Cohn
4c466b425c fix: Change console message to include "use eiscApiAdvanced" 2024-04-25 10:24:09 -04:00
Jason T Alborough
d0aed1c1c5 Merge pull request #1173 from PepperDash/release/1.16.0
Release/1.16.0
2024-04-23 11:17:09 -04:00
Jason T Alborough
bf966121f9 Merge branch 'main' into release/1.16.0 2024-04-01 13:20:55 -04:00
Andrew Welker
ecadb439b2 Merge pull request #1176 from PepperDash/hotfix/ssh-fix
fix: Update PepperDashCore version to 1.3.3-hotfix-390
2024-03-21 09:59:17 -05:00
jtalborough
8c1553a026 fix: Update PepperDashCore version to 1.3.3-hotfix-390 2024-02-26 13:22:35 -05:00
Andrew Welker
9755724342 Merge pull request #1164 from PepperDash/feature/hdps-dm-event-updates
Feature/hdps dm event updates
2024-02-02 08:53:29 -06:00
Andrew Welker
4d25c420e5 Merge pull request #1161 from PepperDash/hotfix/video-codec-base
fix: clear selected causes thread abort in 3 series
2024-02-02 08:52:47 -06:00
Andrew Welker
3190dacdf8 Merge branch 'development' into feature/hdps-dm-event-updates 2024-02-02 08:34:30 -06:00
Andrew Welker
44add9aac6 Merge branch 'main' into hotfix/video-codec-base 2024-02-02 08:33:47 -06:00
Andrew Welker
5bb6405874 Merge pull request #1169 from PepperDash/hotfix/latest-dbs
Hotfix/latest dbs
2024-02-02 08:33:23 -06:00
Andrew Welker
fed3d7e13a Merge branch 'development' into hotfix/latest-dbs 2024-01-25 14:44:35 -06:00
Andrew Welker
af848b9ca4 Merge pull request #1168 from PepperDash/hotfix/latest-dbs 2024-01-25 14:03:48 -06:00
jtalborough
b52c13d8e8 fix: Update PepperDashCore package version to 1.3.2 2024-01-25 13:50:44 -05:00
jtalborough
26f9118154 chore: update PepperDashCore package version 2024-01-25 13:15:12 -05:00
Neil Dorin
2850920d6e feat: Adds IMobileControlMessenger 2024-01-15 15:40:44 -07:00
Neil Dorin
a5de8b14d9 fix: fixes access modifiers on interface 2024-01-11 17:26:35 -07:00
Neil Dorin
9d71810e04 feat: adds methods to IMobileControl3 and adds response message interface 2024-01-11 17:05:34 -07:00
Neil Dorin
bba3c347c6 Merge pull request #1166 from PepperDash/feature/add-cen-io-com-x02
feat: add cen-io-com102 and cen-io-com202 support
2023-12-19 14:45:02 -07:00
jkdevito
be96adcc06 feat: add cen-io-com102 and cen-io-com202 support 2023-12-19 10:50:55 -06:00
Jason DeVito
b245016420 fix: updated dminputchange event debug message 2023-12-14 17:02:14 -06:00
Jason DeVito
19f2c6aa79 fix: update dm event handlers, adds debug statements 2023-12-14 16:32:22 -06:00
Jason DeVito
533ca05ac2 feat: adds additional dm input/output event cases to event handlers 2023-12-14 12:43:46 -06:00
Jason DeVito
9c7777fbaa Merge pull request #1163 from PepperDash/feature/hdpsxxxx-volume-control
Feature/hdpsxxxx volume control
2023-12-13 16:54:59 -06:00
Jason DeVito
5530c91b75 refactor: HdPsXxxOutputAudioController & HdPsXxxAnalogAuxMixerController
- Updated audio controllers to implement `Volume(Feedback).ShortValue`
per documentation for set and get
- Changed `VolumeLevel` set to private set
- Removed `VolumeLevel` and `IsMuted` set from constructors
2023-12-13 16:01:15 -06:00
Jason DeVito
67e0378806 fix: cleanup debug statements 2023-12-13 12:41:45 -06:00
Jason DeVito
1c5aca03d2 fix: resolves hdPsXxx audio controllers scaleWithLimits exception 2023-12-13 12:36:45 -06:00
Nick Genovese
6f5fa2c3b8 fix: clear selected causes thread abort in 3 series
- the old method was using _directoryCode, _directoryTrilist, _directoryJoinmap which were never initialized
2023-12-12 15:29:41 -05:00
Neil Dorin
3d760cbedc feat: adds support for hdcp input control and feedback on Airmedia devices 2023-11-14 16:28:32 -07:00
Jason DeVito
d713abf614 fix: update hd-ps audio controllers to resolve control issues 2023-11-09 23:36:54 -06:00
Jason DeVito
a64b5240ad feat: add output audio controller 2023-11-03 18:14:53 -05:00
Jason DeVito
c528fecb9a feat(wip): add HdPsXxx audio control 2023-11-02 17:52:27 -05:00
jkdevito
355e9cde12 chore(wip): save updates 2023-11-02 11:55:48 -05:00
jkdevito
1df8d3f617 feat: create branch to add volume control 2023-11-02 11:54:44 -05:00
Neil Dorin
2f1caff815 Merge pull request #1154 from PepperDash/hotfix/mpc3-button-list
fix: list available buttons on startup
2023-10-27 12:53:52 -06:00
Jason DeVito
4da2f25c3d fix: list available buttons on startup 2023-10-27 12:14:07 -05:00
Andrew Welker
552a315ac0 Merge pull request #1130 from PepperDash/feature/systemmonitor-programinfo-update
Update systemMonitor class to append Essentials version number
2023-10-26 08:53:06 -06:00
Andrew Welker
99c35f14e1 Merge branch 'development' into feature/systemmonitor-programinfo-update 2023-10-26 07:36:47 -06:00
Andrew Welker
5f2b916220 Merge pull request #1141 from PepperDash/feature/ir-bridge-map
Add default IR join map using Crestron IR File naming conventions DEV
2023-10-26 07:36:25 -06:00
Andrew Welker
c7a16a46e9 Merge branch 'development' into feature/ir-bridge-map 2023-10-25 20:39:46 -06:00
Andrew Welker
d6334538c0 Merge pull request #1142 from PepperDash/feature/ir-bridge-map
Add default IR join map using Crestron IR File naming conventions
2023-10-25 20:38:39 -06:00
jkdevito
4f64022623 fix: update duplicate joinMap prooperties causing build errors 2023-10-25 17:25:14 -05:00
Andrew Welker
7ad638ea9a Merge branch 'development' into feature/systemmonitor-programinfo-update 2023-10-25 16:02:00 -06:00
Andrew Welker
51d168b1d5 Merge pull request #1147 from PepperDash/hotfix/mpc3Touchpanel-updates
refactor: update init methods and add events
2023-10-25 16:00:21 -06:00
Andrew Welker
3179f3bf59 Merge branch 'development' into hotfix/mpc3Touchpanel-updates 2023-10-25 15:36:28 -06:00
Andrew Welker
eba27d016d Merge pull request #1144 from PepperDash/feature/add-secureTcpClient-to-commFactory
Add secureTcpClient to comm factory DEV
2023-10-25 15:36:08 -06:00
Andrew Welker
e5fe16122f Merge branch 'development' into feature/add-secureTcpClient-to-commFactory 2023-10-25 15:20:37 -06:00
Andrew Welker
ee9b191f85 Merge branch 'main' into feature/ir-bridge-map 2023-10-25 14:51:29 -06:00
Jason DeVito
d1d1d81165 fix: update registration debug statement to include response 2023-10-25 15:44:39 -05:00
Jason DeVito
6698dcb46e refactor: update init methods and add events
- Updated InitializeButton method to enable/disable buttons based on config.
- Updated InitializeButtonFeedback method debug statements.
- Added BaseEvent event subscription.
- Added PanelStateChnage event subscription.
2023-10-25 15:26:42 -05:00
Jason DeVito
c8aa77fbc0 Merge pull request #1146 from PepperDash/hotfix/hdpsxxx-executeswitcher-object
Hotfix/hdpsxxx executeswitcher object
2023-10-24 15:56:48 -05:00
Jason DeVito
53b96d54e6 fix: removes old selector casting statements 2023-10-24 15:36:04 -05:00
Jason DeVito
6c41b8e19d fix: updates executeSwitch, add helper method
1. Updated executeSwitch object casting to resolve routing issues.
2. Added ListRoutingPorts method.
2023-10-24 15:24:44 -05:00
Jason DeVito
922119fdd6 refactor: updated IR joins. 2023-10-14 22:20:11 -05:00
Andrew Welker
86c1faa7cd Merge branch 'development' into feature/add-secureTcpClient-to-commFactory 2023-10-10 10:43:32 -05:00
Andrew Welker
75895604ed Merge pull request #1143 from PepperDash/feature/add-secureTcpClient-to-commFactory
Add secureTcpClient to comm factory
2023-10-10 10:41:03 -05:00
jdevito
de6f8c7896 feat: adds secureTcpClient to comm factory 2023-10-10 06:07:37 -05:00
jdevito
5a5e24a921 fix: clears joinMap.Joins and rebuilds with matching IR commands of the file loaded 2023-10-07 19:54:56 -05:00
jdevito
8b3bc523d2 fix: removes if blocking PrintAvailableCommands 2023-10-07 19:39:58 -05:00
jdevito
ff04d49a1b fix: updates debug level and removes unused code 2023-10-07 19:26:14 -05:00
jdevito
55af6a96f6 feat(wip): updates bridge join map descriptions
Updated bridge join map descriptions to match the IR standard command name.
2023-10-07 19:25:04 -05:00
jdevito
a3561bc89b feat(wip): updates GenericIrController and IrOutputPortController to implement bridge map 2023-10-07 19:16:03 -05:00
jdevito
1a123ab6dc feat: adds GenericIrControllerJoinMap 2023-10-07 16:54:29 -05:00
jdevito
c0b0b35f6d feat(wip): seeds feature for IR signal bridge map 2023-10-07 16:51:27 -05:00
Andrew Welker
1d60f2e069 Merge pull request #1140 from PepperDash/hotfix/huddle-room-interfaces
Break IEssentialsRoom down further
2023-09-29 09:14:37 -05:00
Andrew Welker
bd97676050 Merge branch 'development' into hotfix/huddle-room-interfaces 2023-09-28 16:59:04 -05:00
Neil Dorin
8612fab4fe Merge pull request #1138 from PepperDash/hotfix/huddle-room-interfaces
Break IEssentialsRoom down further
2023-09-28 15:26:44 -06:00
Andrew Welker
b9fd9f23a4 refactor: break IEssentialsRoom down further
In order to allow for easier composition of interfaces for room plugins, the IEssentialsRoom interface needed to be broken down further to the simplest components a room would need to function. The interfaces are composited in the huddle space and the Huddle VTC interfaces.
2023-09-28 15:42:38 -05:00
Andrew Welker
1e07e44279 Merge pull request #1135 from PepperDash/feature/hdpsXxx-fixes
Feature/hdps xxx fixes
2023-09-20 16:07:11 -05:00
Jason DeVito
1569c12450 fix: Updates SetupOutputs method
Corrects the port referencece to exclude `.StreamCec` when
building the port.
2023-09-20 15:41:06 -05:00
Jason DeVito
6d020132cf refactor: GetCecPort method to handle exceptions 2023-09-20 15:38:25 -05:00
Jason DeVito
7ecb2ecf6d fix: updates SetupOutputs to create a hdmiOutX and dmLiteOutX port 2023-09-13 16:43:23 -05:00
Jason DeVito
393033b6c9 refactor: Updates HdPsXxxController class
- Modifies `SetupInput()` and `SetupOutput()`
- Renames `GetInputPriorities()` to `SetInputPriorities()`
2023-09-13 10:13:39 -05:00
Jason DeVito
9fb16f30b0 refactor: Changes IRoutingHasSync interface
- Changed IRoutingHasSync interface to IRoutingHasVideoInputSyncFeedbacks.
- Remvoed IRoutingHasSynDelegate
- Added interface to HdPsXxxController class
2023-09-13 10:02:20 -05:00
Jason DeVito
8b6a9db7e0 refactor: refactors GetCecPort method 2023-09-13 09:32:44 -05:00
Jason DeVito
5a67a4060d feat: adds routing sync provider interface and delegate 2023-09-13 09:31:25 -05:00
Jason DeVito
0fad667fab fix: adds additional debug statements when attempting to get feedback property for device 2023-09-13 09:29:51 -05:00
Andrew Welker
95c37872ad Merge pull request #1132 from PepperDash/hotfix/mpc3-keypad-processor
Update MPC3 Touchpanel Controller DEV
2023-09-13 09:28:03 -05:00
Andrew Welker
a5ad7ea48b Merge branch 'development' into hotfix/mpc3-keypad-processor 2023-09-13 08:51:55 -05:00
Andrew Welker
14221f9613 Merge pull request #1133 from PepperDash/feature/crestron-hdps401-switcher
Add support for HD-PSXXX switchers
2023-09-13 08:50:40 -05:00
Jason DeVito
334a62c329 fix: wraps GetDeviceForKey and GetFeedbackProperty methods in a try/catch 2023-09-13 08:32:07 -05:00
Jason DeVito
e590c7cedb feature(wip): adds inputPriorities configuration property 2023-09-12 19:26:55 -05:00
Jason DeVito
189c470603 feature(wip): adds inputPriorities configuration property 2023-09-12 17:10:25 -05:00
Andrew Welker
4deee11d15 Merge branch 'development' into hotfix/mpc3-keypad-processor 2023-09-12 14:53:29 -05:00
Andrew Welker
4bdac8d9e9 Merge pull request #1131 from PepperDash/hotfix/mpc3-keypad-processor
Update MPC3 Touchpanel Controller
2023-09-12 14:53:04 -05:00
Andrew Welker
58e019992a Merge branch 'development' into feature/crestron-hdps401-switcher 2023-09-12 14:50:42 -05:00
Jason DeVito
da5d2d74f2 fix: removes OutputPort.InputPriorities reference 2023-09-12 14:36:17 -05:00
Jason DeVito
2afa9df705 fix: removes HdPsXxx controller, propertiesConfig and join map 2023-09-12 14:08:20 -05:00
Jason DeVito
1aa9590587 feature: adds DmInputChange event 2023-09-12 13:23:18 -05:00
Jason DeVito
27bac4e83d fix(wip): updates stream cec implementation to handle switchers with multiple outputs 2023-09-12 10:09:37 -05:00
Jason DeVito
4e33743f50 refactor: SetupInput() and SetupOutput() methods to set standard keys for ports that are instantiated 2023-09-11 19:24:21 -05:00
Jason DeVito
08af6370a6 fix(wip): adds Debug.Console() statements to identify keys per input; adds ICec interface, pending implementation 2023-09-11 15:48:34 -05:00
Jason DeVito
97c0bddb48 fix(wip): refactors SetupInputs() and SetupOutputs() to handle io types 2023-09-11 14:49:46 -05:00
Jason DeVito
316d545bda refactor(wip): updates keypad initializeFeedbacks method 2023-09-08 15:20:29 -05:00
Jason DeVito
13df52ab49 refactor(wip): updates constructor postActiviate call to seperate methods for enabling/disabling buttons and feedbacks 2023-09-08 13:47:34 -05:00
Jason DeVito
527457baf5 refactor(wip): MPC3 class refactor constructor 2023-09-08 13:00:27 -05:00
Jason DeVito
d74c5de651 wip: updates to HdPsXxx class while test implementation to resolve exceptions 2023-09-08 10:51:19 -05:00
Jason DeVito
b06d0c0deb fix: resolves typo of hdpsXxx type name in the factory 2023-09-07 18:37:21 -05:00
jdevito
759fb1d729 feature: adds support for HdSpXxx switchers
WIP: added support for HD-PS401, HD-PS402, HD-PS621 and HD-PS622,
pending testing with device.
2023-09-06 11:22:19 -05:00
Neil Dorin
3defd6b41b Merge pull request #1129 from PepperDash/hotfix/codec-joinable-dialable
fix: add Dialable property to Meeting class DEV
2023-08-29 09:50:08 -06:00
Andrew Welker
794cd3be5f Merge branch 'development' into hotfix/codec-joinable-dialable 2023-08-29 08:09:37 -06:00
Andrew Welker
68cbbee6a3 Merge pull request #1128 from PepperDash/hotfix/codec-joinable-dialable
fix: add `Dialable` property to Meeting class
2023-08-29 08:09:27 -06:00
Andrew Welker
a50d758f70 Merge pull request #1127 from PepperDash/hotfix/pd-core-ssh-fix
Hotfix/pd core ssh fix
2023-08-28 16:14:33 -06:00
Andrew Welker
aedac14feb Merge branch 'development' into hotfix/pd-core-ssh-fix 2023-08-28 15:23:19 -06:00
Andrew Welker
93134cae5c fix: add Dialable property to Meeting class
Previously, the meeting class was determining Dialable based on a meeting ID being "0". This is a Zoom-specific thing, but it has recently become a thing for Cisco codecs to have meetings that aren't necessarily dialable. Adding this property to the `Meeting` class allows the specific codec type to set it correctly based on that codec's needs.
2023-08-28 15:20:57 -06:00
Andrew Welker
555915b151 Merge pull request #1126 from PepperDash/hotfix/pd-core-ssh-fix
Hotfix/pd core ssh fix
2023-08-25 09:01:17 -06:00
Andrew Welker
fa0f006b9b Merge branch 'main' into hotfix/pd-core-ssh-fix 2023-08-25 08:40:07 -06:00
Nick Genovese
4c0fb6311b fix: set core version to 1.3.1 2023-08-24 08:15:31 -04:00
Neil Dorin
6538cecc3b Merge pull request #1125 from PepperDash/hotfix/pdu-bridge-issues
Custom Join Map Improvements DEV
2023-08-21 16:14:11 -06:00
Neil Dorin
44296cbc54 Merge branch 'development' into hotfix/pdu-bridge-issues 2023-08-21 16:00:24 -06:00
Neil Dorin
0dcf45fc84 Merge pull request #1124 from PepperDash/hotfix/pdu-bridge-issues
Custom Join Map Improvements
2023-08-21 16:00:03 -06:00
Andrew Welker
4d2ce83e75 fix: rework setting custom join data
The previous method was causing an Exception to be thrown if a join didn't exist in the default join map for a device. This exception would prevent other devices from linking to a bridge correctly. This method now allows for join names to not be matched and the method will keep going.
2023-08-21 15:27:25 -06:00
Andrew Welker
da4070bad0 docs: correct PDU Online join name for printing 2023-08-21 15:23:33 -06:00
Andrew Welker
d95692ba96 Merge pull request #1121 from PepperDash/hotfix/vtc-room-activation-deactivation-changes
Hotfix/vtc room activation deactivation changes
2023-08-17 10:44:58 -06:00
Nick Genovese
daf3f321bd fix: bumped core version
- bumped core to 1.3.1-hotfix-337 for ssh fixe
2023-08-16 10:25:26 -04:00
Andrew Welker
269d82227d Merge branch 'development' into hotfix/vtc-room-activation-deactivation-changes 2023-08-15 12:50:19 -06:00
Andrew Welker
e8f20a4ca3 Merge pull request #1123 from PepperDash/hotfix/crestron-db-updates
Update Crestron DBS & PD Core DEV
2023-08-15 12:50:07 -06:00
Andrew Welker
5fbacadd7f Merge branch 'development' into hotfix/crestron-db-updates 2023-08-15 12:25:49 -06:00
Andrew Welker
9c9b2952aa Merge pull request #1122 from PepperDash/hotfix/crestron-db-updates
Update Crestron DBS & PD Core
2023-08-15 12:25:37 -06:00
Andrew Welker
a7a4b75382 Merge branch 'main' into hotfix/crestron-db-updates 2023-08-15 11:00:27 -06:00
Andrew Welker
8d0f0c0c37 Merge branch 'development' into hotfix/vtc-room-activation-deactivation-changes 2023-08-15 10:59:46 -06:00
Andrew Welker
2b97b9bdc4 Merge pull request #1114 from PepperDash/feature/DeviceNetworkInformationUpdates
Add Static Class for device network information and supporting extension methods
2023-08-15 10:59:06 -06:00
Andrew Welker
77f5dafdfe Merge pull request #1110 from PepperDash/hotfix/DmRmcScalerCVideoMute
Add support for VIdeo Mute to DM-RMC-4K-SCALER-C
2023-08-15 10:58:52 -06:00
Andrew Welker
b5bf87c634 build: update PD Core version 2023-08-15 10:02:42 -06:00
Andrew Welker
62f175c24a chore: trigger build with new Crestron DBs 2023-08-15 09:38:34 -06:00
Andrew Welker
0cfcf61d6b Merge branch 'main' into hotfix/DmRmcScalerCVideoMute 2023-07-27 12:05:32 -06:00
Andrew Welker
4a0bacb27e Merge branch 'development' into feature/DeviceNetworkInformationUpdates 2023-07-21 12:23:42 -06:00
Andrew Welker
a36901894d Merge pull request #1111 from PepperDash/feature/AddUsbCConnector
Add USB-C and HdBaseT Options for Routing Ports
2023-07-21 12:23:30 -06:00
Andrew Welker
c047507997 Merge branch 'development' into hotfix/vtc-room-activation-deactivation-changes 2023-07-21 12:22:58 -06:00
Andrew Welker
ef719b0a64 Merge pull request #1120 from PepperDash/hotfix/vtc-room-activation-deactivation-changes
Hotfix/vtc room activation deactivation changes
2023-07-21 12:22:47 -06:00
Neil Dorin
c46409dc3f Minor adjustments and added debug messages 2023-07-19 16:55:53 -06:00
Neil Dorin
f73d6994b8 Additional updates to allow occupancy sensor to be cleared when room not active 2023-07-19 16:22:20 -06:00
Neil Dorin
a787be6ccc Updates Vtc1 room types to allow for deactivation/activation 2023-07-19 15:28:24 -06:00
Neil Dorin
f0ae0094dc Adds optional enable property to partition sensor config and defaults to enable 2023-07-19 09:50:48 -06:00
Trevor Payne
fcd4b5d772 Merge pull request #1118 from PepperDash/hotfix/AirMediaRegistration
Fix Airmedia Registration Issue
2023-07-12 12:52:56 -05:00
Trevor Payne
c3ba6d5c28 fix: fix issue where the customactivate for the base class was beig suppressed in airmedia controllers 2023-07-12 12:27:38 -05:00
Trevor Payne
3f6b2f05a2 feature: Add Static Class to assist with getting network information about connected devices
feature: Add overload to 'Contains' extension method to allow for some more verbose comparisons

feature: Add 'TrimAll' string extension method to TrimStart and TrimEnd with an overload to set the character to trim

docs: improve XML summary comments for string extensions
2023-07-04 23:53:31 -05:00
jdevito
cab0b01a08 fix: updates systemMonitor class to append Essentials version number to the ProgramName that is passed across the bridge 2023-06-27 15:20:01 -05:00
Trevor Payne
f4af1b6e7c feature: Add HdBaseT as a eRoutingPortConnectionType 2023-06-16 14:57:48 -05:00
Trevor Payne
a04bfd1fcb feature: Add HdBaseTIn and HdBaseTOut as RoutingPortNames 2023-06-16 14:56:21 -05:00
Trevor Payne
faaf8151df Merge branch 'feature/AddUsbCConnector' of https://github.com/PepperDash/Essentials into feature/AddUsbCConnector 2023-06-16 14:50:52 -05:00
Trevor Payne
0ee6322684 feature: Add USBCIn and Out Names for RoutingPortNames 2023-06-16 14:50:10 -05:00
Trevor Payne
c614347f29 Merge branch 'main' into feature/AddUsbCConnector 2023-06-16 14:29:02 -05:00
Trevor Payne
43f06d2167 feature: Add USB-C as eRoutingPortConnectionType option 2023-06-16 14:26:52 -05:00
Andrew Welker
2ffe24fd93 Merge branch 'main' into hotfix/DmRmcScalerCVideoMute 2023-06-07 12:12:26 -06:00
mhengeli
515ffd07f0 fix: added complimentary link for mute off. fix: Update references 2023-06-07 13:16:06 -04:00
mhengeli
16ea7a88be fix: updated Core references 2023-06-07 12:22:03 -04:00
Andrew Welker
e1ce35863f Merge pull request #1109 from PepperDash/release/1.14.0
Release/1.14.0
2023-06-07 10:11:49 -06:00
Andrew Welker
acd3bad1f2 Merge pull request #1108 from PepperDash/release/1.14.0
1.14.0
2023-06-07 09:54:34 -06:00
mhengeli
0f3b0580f0 feat: add videomute on/off for rmc scaler c 2023-06-07 09:45:25 -04:00
Andrew Welker
08514915b2 Merge branch 'main' into release/1.14.0 2023-05-09 10:22:08 -06:00
Andrew Welker
ea464038b9 Merge pull request #1106 from PepperDash/hotfix/remove-old-workflow
Hotfix/remove old workflow
2023-04-27 13:13:37 -06:00
Andrew Welker
c4c44d02f5 Merge branch 'development' into hotfix/remove-old-workflow 2023-04-27 12:54:18 -06:00
Andrew Welker
3fe5d89904 Merge pull request #1105 from PepperDash/hotfix/remove-old-workflow
Delete add-issues-to-project.yml
2023-04-27 12:54:08 -06:00
Jason T Alborough
c0d78e8978 Delete add-issues-to-project.yml 2023-04-27 13:59:36 -04:00
Neil Dorin
3716dd0824 Merge pull request #1104 from PepperDash/hotfix/dm-build-issues
Enable DM TX/RX builds for blade chassis DEV
2023-04-27 10:22:15 -06:00
Andrew Welker
ebe8ee5653 Merge branch 'development' into hotfix/dm-build-issues 2023-04-27 09:55:26 -06:00
Andrew Welker
432934ad00 Merge pull request #1103 from PepperDash/hotfix/dm-build-issues
Enable DM TX/RX builds for blade chassis
2023-04-27 09:55:08 -06:00
Andrew Welker
372cf86613 Merge pull request #1100 from PepperDash/feature/IHasBatteryStats
Add Interfaces for Battery Status Tracking
2023-04-27 09:51:15 -06:00
Andrew Welker
67c99a9ad4 Merge branch 'development' into feature/IHasBatteryStats 2023-04-27 09:26:56 -06:00
Andrew Welker
31085d42a9 Merge pull request #1099 from PepperDash/hotfix/DisplayPortHdcp
Resolve Issues with HDCP Displayport
2023-04-27 09:26:41 -06:00
Andrew Welker
0df315426b fix: use new interface for parentDev
The GetDmRmcController & GetDmTxController methods were
previously ignoring the `DmBladeChassisController` type.
This was causing transmitters connected to a DM blade chassis to
not be built,
2023-04-26 13:32:49 -06:00
Andrew Welker
6ddbdd90c7 feat: add new interface and update Chassis controllers 2023-04-26 13:32:18 -06:00
Andrew Welker
39e1e5167b Merge branch 'development' into hotfix/DisplayPortHdcp 2023-04-20 11:51:21 -06:00
Trevor Payne
7f916d1d2f refactor: change IHasPowerCycleWithBatteries to IHasPowerCycleWithBattery for clarity 2023-04-20 12:31:50 -05:00
Trevor Payne
7c7f087898 feature: added additional parameters to IHasPowerCycleWithBatteries 2023-04-20 12:29:34 -05:00
Trevor Payne
898dab1d9a feature: add several interfaces for battery status on devices
refactor: mark existing PDU interfaces in PepperDash_Essentials_Core.Devices as obsolete

refactor: replicate existing PDU interfaces in PepperDash.Essentials.Core
2023-04-20 12:21:45 -05:00
Andrew Welker
b221d2f0cb Merge pull request #1098 from PepperDash/hotfix/DisplayPortHdcp
Resolve Issues with HDCP Displayport
2023-04-19 08:20:02 -06:00
Trevor Payne
9656269826 fix: resolve issue where displayport hdcp event not registered properly
fix: resolve issue where feedback from Displayport HDCP capability was improperly named
2023-04-17 22:27:56 -05:00
Trevor Payne
ba182c1d98 Merge pull request #1094 from PepperDash/hotfix/ConsoleCommandFixes
Fix Console Response Line Errors
2023-04-14 14:08:02 -05:00
Andrew Welker
2460290dc1 Merge branch 'main' into hotfix/ConsoleCommandFixes 2023-04-14 12:39:29 -06:00
Andrew Welker
0b01661196 Merge pull request #1093 from PepperDash/hotfix/rmcEnhancements
Enhance Endpoint HDCP Functionality
2023-04-14 12:35:27 -06:00
Trevor Payne
dfa55ab9f8 fix: update console responses to properly use explicit NewLine characters
fix: Resolve #1084
2023-04-14 12:18:06 -05:00
Trevor Payne
55ad92e2f6 feature: enhance 4K DM Endpoint HDCP functionality
feature: add bridge join to report number of HDCP inputs

feature: Resolve #1088

feature: Resolve #1089
2023-04-14 11:41:32 -05:00
Andrew Welker
c53cad8119 Merge pull request #1086 from PepperDash/hotfix/pd-core-update-ssh-issues
Update PD Core to 1.2.1 DEV
2023-04-07 11:52:23 -06:00
Andrew Welker
82e8b4b203 Merge branch 'development' into hotfix/pd-core-update-ssh-issues 2023-04-07 11:37:31 -06:00
Andrew Welker
8965752025 Merge pull request #1085 from PepperDash/hotfix/pd-core-update-ssh-issues
Update PD Core to 1.2.1
2023-04-07 11:37:20 -06:00
Andrew Welker
8c3b891255 Merge pull request #1082 from PepperDash/feature/vc4-fileio
Update VC4 file handling
2023-04-07 11:25:01 -06:00
Andrew Welker
51bd95937a build: update PD Core version
SSH issues were found in PD Core 1.2.0 that were causing
issues with manual disconnection/reconnection instead of
using the autoreconnect timer. The fix for this issue
was added in PD COre 1.2.1
2023-04-07 11:20:08 -06:00
jtalborough
10fc8ee30b Merge remote-tracking branch 'origin/feature/vc4-fileio' into development 2023-03-28 16:26:32 -04:00
Andrew Welker
8da8b8c584 Merge pull request #1080 from PepperDash/hotfix/dge-hdcp
Add HDCP & Bridging support for DGE Devices DEV
2023-03-27 16:40:39 -06:00
Andrew Welker
c7e0326b8c Merge branch 'development' into hotfix/dge-hdcp 2023-03-27 16:27:16 -06:00
Neil Dorin
845978c741 Merge pull request #1079 from PepperDash/hotfix/dge-hdcp
Add HDCP & Bridging support for DGE Devices
2023-03-27 15:01:54 -06:00
Andrew Welker
ba511067d3 fix: add missing feedback links 2023-03-27 14:13:15 -06:00
Andrew Welker
a9fe8bbb10 refactor: move DGE200 factory out of DGE200 class 2023-03-27 13:59:13 -06:00
Andrew Welker
bc64ee37cb feat: Add bridging & HDCP support for DGE 2023-03-27 13:58:46 -06:00
Andrew Welker
b2646f50cb feat: add DGE Join map 2023-03-27 13:57:25 -06:00
Neil Dorin
465aa947cf Merge pull request #1078 from PepperDash/release/1.13.0
1.13.0 DEV
2023-03-24 13:08:18 -06:00
Neil Dorin
16b78d27b9 Merge pull request #1077 from PepperDash/release/1.13.0
1.13.0
2023-03-24 13:05:33 -06:00
Andrew Welker
4e56213dad Merge pull request #1066 from thombrooks/main
Delete IEssentialsHuddleSpaceRoom.cs
2023-03-23 12:44:14 -06:00
Neil Dorin
668fc89eb2 Merge pull request #1076 from PepperDash/feature/DisplayPortHdcp
Add support for DisplayPort HDCP Control to DM-TX-4Kz-302C
2023-03-22 12:56:29 -06:00
Andrew Welker
e623c482a9 refactor: modify feedback for HDCP capability 2023-03-22 11:40:02 -06:00
Trevor Payne
243c7cc3ee feat: Add HDCP capability feedback and setting to Displayport Input on 4xz302 endpoint
feat: Resolve #1073
2023-03-22 11:39:57 -06:00
Andrew Welker
615598c8a6 Merge pull request #1075 from PepperDash/feature/AM3200
Add support for Crestron AM3200
2023-03-22 11:35:52 -06:00
Andrew Welker
3b25108a26 Merge branch 'development' into feature/AM3200 2023-03-22 11:05:43 -06:00
Andrew Welker
f253abd0ae fix; add check for HdmiIn being null
Not all Airmedia devices that might use this class have
an HDMI input. This check should prevent null ref
exceptions from happening.
2023-03-22 10:53:57 -06:00
Andrew Welker
e04f6d0396 refactor: move to switch for event 2023-03-22 10:53:36 -06:00
Andrew Welker
eb4c7ff605 Merge pull request #1063 from PepperDash/feature/dmps-dm-fixes
Various DMPS fixes
2023-03-22 10:52:18 -06:00
Andrew Welker
d0688cbc16 refactor: simplify feedback & event subscription 2023-03-22 10:36:10 -06:00
Andrew Welker
961af69aae chore: update PD Core version 2023-03-22 10:35:48 -06:00
Andrew Welker
df402ce498 Merge branch 'development' into feature/dmps-dm-fixes 2023-03-22 10:20:56 -06:00
Andrew Welker
e524bf358a Merge pull request #1070 from PepperDash/feature/system-monitor-bridge-updates
System Monitor Bridge updates
2023-03-22 10:20:42 -06:00
Andrew Welker
3abd195c57 Merge branch 'development' into feature/system-monitor-bridge-updates 2023-03-22 09:59:30 -06:00
Andrew Welker
a3615d8d1b Merge pull request #1069 from PepperDash/feature/cws
Feature/cws
2023-03-22 09:59:16 -06:00
Andrew Welker
6a461a6923 Merge branch 'development' into feature/cws 2023-03-22 09:42:39 -06:00
Andrew Welker
77776f3258 Merge pull request #1068 from PepperDash/feature/ConsoleImprovements
Update console commands to use ConsoleCommandResponse
2023-03-22 09:36:26 -06:00
Trevor Payne
701513d30e feat: add AM3200 to AirMediaController factory type list
fix: adjust event callback to recognize events thrown by AM3x00 devices
2023-03-16 17:11:44 -05:00
jdevito
c9eaff6fce fix: updated Devlist handler to add constructor enabling CORS support 2023-02-20 16:59:05 -06:00
jdevito
e8cdf3a63b fix: updated handlers, removed handler methods that are not implemented, added constructor to implement CORS support 2023-02-20 16:44:11 -06:00
jdevito
f55ecdb67e fix: updated debug constants 2023-02-20 15:46:57 -06:00
Trevor Payne
cad677ae89 feat: updated all console responses in SetDeviceStreamDebugging to use ConsoleResponse 2023-02-17 23:07:16 -06:00
Trevor Payne
b057d3de18 feat: update GetRoutingPorts to use ConsoleResponse 2023-02-17 23:06:15 -06:00
Trevor Payne
1920d37488 feat: update reportVersions command to use ConsoleResponse
feat: update gettypes to use ConsoleResponse
2023-02-17 23:02:54 -06:00
Trevor Payne
e005a30383 feat: improved console responses in JoinMapBase 2023-02-17 22:59:20 -06:00
Andrew Welker
058b3820be Merge branch 'development' into feature/dmps-dm-fixes 2023-02-17 09:07:13 -07:00
Andrew Welker
8a77b134e4 Merge pull request #1067 from PepperDash/feature/joinmapReportingImprovements
Cleanup getjoinmap console return
2023-02-17 09:02:04 -07:00
Trevor Payne
88f843250a feat: cleanup getjoinmap console return
resolves: Issue #928
2023-02-17 00:47:50 -06:00
thombrooks
772369bcd6 Delete IEssentialsHuddleSpaceRoom.cs
Redundant - correct definitions are in the Interfaces subfolder.
2023-02-14 20:16:01 -06:00
Alex Johnson
cef29af1ba Add register for basic DM endpoints to constructor stage due to requirement they are registered before parent devices. 2023-02-08 20:59:30 -05:00
Alex Johnson
8cc6cfafe9 Fixes CEvent in InitializeSystem() to properly wait for initialization until all devices are registered, if the system is a DMPS. This fixes an issue where HDBaseT type endpoints were not working on a DMPS3 non-4K unit. 2023-02-08 16:19:17 -05:00
Andrew Welker
89ba4627ea Merge pull request #1060 from PepperDash/feature/cws
Add support for EWS to Essentials
2023-02-07 09:58:08 -07:00
Andrew Welker
e05186defd chore: update packages to use 1.1.5-beta-317 2023-02-07 09:33:46 -07:00
Andrew Welker
83b0aec227 Merge branch 'feature/cws' of https://github.com/PepperDash/Essentials into feature/cws 2023-02-07 09:23:53 -07:00
Andrew Welker
a3ba014c0f Merge branch 'development' into feature/cws 2023-02-07 09:06:45 -07:00
jdevito
4919a863c3 System Monitor Bridge updates
Add processor reboot to join map and controller class.

Add program reset to join map and controller class.
2023-02-02 17:58:08 -06:00
Neil Dorin
2228bc1a1e Merge pull request #1057 from PepperDash/hotfix/video-codec-base-updateDirectoryXsig
fix: updates to resolve directory issues DEV
2023-02-02 11:48:57 -07:00
Neil Dorin
1411add591 Merge pull request #1056 from PepperDash/hotfix/video-codec-base-updateDirectoryXsig
fix: updates to resolve directory issues
2023-02-02 11:48:36 -07:00
jdevito
cbec2f2119 fix: updates to resolve directory issues
updateDirectoryXsig logic to resolve showing contacts in root when
folders are in use (ZoomRooms).

LinkVideoCodecDirectoryToApi to resolve analog value driving
total number of contacts when folders are in use (ZoomRooms).

ConvertZoomContactsToGeneric to reference roomFolder.FolderId and
contactFolder.FolderId in foreach loops.
2023-02-02 12:31:11 -06:00
jdevito
34d3b705fa fix: aded GetPaths method call when running on a server 2023-02-01 15:30:21 -06:00
jdevito
e1d7374f1e fix: resolved issues with setDeviceStreamDebug; refactor: added static method GetRequestBody 2023-02-01 13:22:12 -06:00
jdevito
a3346d5ef4 refactor: added 400 bad request responses 2023-02-01 12:22:52 -06:00
jdevito
1c1eabcef6 refactor: cleaned up unused using statements 2023-02-01 12:02:05 -06:00
jdevito
12f3f519cc refactor: cleaned up devprops handler 2023-02-01 11:58:22 -06:00
jdevito
4dc6d5b5ac refactor: devlist request handler, added static method for creating list 2023-02-01 11:50:26 -06:00
jdevito
faaa2a354e refactor: removed debug statements, added 400 return if request content length is < 0 2023-02-01 11:34:36 -06:00
jdevito
087e74b207 fix: removed json serial settings 2023-02-01 11:32:19 -06:00
jdevito
8bb670c43b fix: changed response status to 500 if loaded assemblies is null 2023-02-01 11:31:52 -06:00
jdevito
55a5cc53c9 refactor: moved and renamed GetJoinHelper class to EssentialsWebApiHelpers, added func for loaded assemblies 2023-02-01 11:30:35 -06:00
jdevito
0793a09095 feat: added static methods for GetJoinMaps, added GetFeedbacksForDevice request handler 2023-02-01 11:15:13 -06:00
jdevito
15efed02a5 fix: resolved issue with GetTypes request handlers causing a 500 error response; updated debug constants to default levels 2023-02-01 09:43:52 -06:00
jdevito
c68d46f971 fix: Updated showconfig, gettypes, getjoinmap handlers; updated BridgeBase to expose joinmaps; updated DeviceFactory to introduce method for getting dictionary 2023-01-31 18:27:14 -06:00
jdevito
dd2aca9aa4 feat: worked on adding get/post for appdebug, devprops, devjson, disableallstreamdebug, setdevicestreamdebug 2023-01-30 22:08:13 -06:00
jdevito
705e750419 fix: resolved issue with default handlers, removed debug statements that were not accessed; fix: updated default handler, reportversions handler, devlist handler 2023-01-30 17:17:12 -06:00
Neil Dorin
23af38aefa Merge pull request #1054 from PepperDash/hotfix/project-workflow
feature: add workflow to push to project
2023-01-30 15:26:16 -07:00
jta
1bae7dc91b feature: add workflow to push to project 2023-01-30 15:19:14 -05:00
jdevito
0c2896f9aa fix: updated packages.config to reference PepperDashCore.1.1.5-alpha-291, built on latest development branch; removed empty constructor from request handlers 2023-01-24 12:22:40 -06:00
jdevito
555944011d fix: added continue to resolve warning of possible empty statement when compiled locally 2023-01-19 12:19:27 -06:00
jdevito
03d5c24dc4 fix: updated Essentials WebAPI and Request Handlers using statements to reflect PepperDash Core updates in 1.1.5-alpha-286 2023-01-19 12:00:32 -06:00
jdevito
f4a5d6737e fix: updated packages.config reference for PepperDash_Core to latest WebAPI build 2023-01-19 11:50:48 -06:00
jdevito
b52bee5714 refactor: Changed CWS references to WebApi, re-organized Web folder; added generic request handlers to align with API, handlers need to be completed 2023-01-18 15:26:24 -06:00
Alex Johnson
5de4382cd0 Fixes for hdbaset endpoints on DMPS3 non-4k chassis. Adds ability to connect Essentials room volumes to DMPS volume control. 2023-01-18 15:45:42 -05:00
jdevito
6414631deb feat: added crestron web server (cws) to Essentials_Core 2023-01-17 09:49:16 -06:00
Neil Dorin
300c675341 Merge pull request #1052 from PepperDash/release/v1.12.7
Release/v1.12.7
2023-01-11 13:30:43 -07:00
Neil Dorin
a4290e68b1 Merge branch 'main' into release/v1.12.7 2023-01-11 13:05:09 -07:00
Trevor Payne
c14e5fe449 fix: issue registering versiport digital outputs 2023-01-11 13:57:25 -06:00
jta
3b2fa8aec5 fix: issue with file path on four sereis
refactor: remove redundnet /
2023-01-09 17:16:03 -05:00
jta
ffa864c71b Merge remote-tracking branch 'origin/development' into feature/vc4-fileio 2023-01-09 15:45:38 -05:00
Andrew Welker
86f904c8f9 Merge pull request #1050 from PepperDash/hotfix/zoom-phonebook-issues
Fix Empty Zoom Phonebook DEV
2022-12-22 15:29:27 -07:00
Andrew Welker
6b60f4ddb1 Merge branch 'development' into hotfix/zoom-phonebook-issues 2022-12-22 14:02:18 -07:00
Neil Dorin
2677d63553 Merge pull request #1049 from PepperDash/hotfix/zoom-phonebook-issues
Fix Empty Zoom Phonebook
2022-12-22 13:52:45 -07:00
Andrew Welker
d03581fea8 fix: change contact message handling
On some occasions when the Zoom Room restarted
and Essentials did not, the directory could be
requested while the Zoom Room had no contacts
yet, as it hadn't received them from Zoom Cloud.
This caused the directory to be empty, even
though there may be valid contacts. Now,
Essentials uses the Added Contact and Updated Contact
methods to fire the directory changed event, allowing
for directory updates to be propogated as necessary.
2022-12-22 08:54:24 -07:00
Andrew Welker
decc8ed3a5 refactor: update queue error handling
On some occasions, a ThreadAbortException was being
caught on shutdown and causing exceptions to be printed
needlessly. Messaging has also been updated to remove
personal pronouns.
2022-12-22 08:52:58 -07:00
Andrew Welker
b0637288e9 refactor: move logic for updating directory to method 2022-12-21 12:21:01 -07:00
Trevor Payne
ea8c3995bd Merge pull request #1048 from PepperDash/feature/Add-DinIo8
Remove references to pullup resistors in versiport digital outputs
2022-12-21 10:39:27 -06:00
Andrew Welker
f6e08eb077 Merge branch 'development' into feature/Add-DinIo8 2022-12-21 09:25:53 -07:00
jta
112a2b7382 feature: fileio now uses Global.FilePathPrefix as its directory
All read wirtes now use the current working essentials directory. This resolves issues between 3 series, 4 series, and VC-4
2022-12-20 15:16:18 -05:00
Andrew Welker
c2d49c65f0 Merge pull request #1047 from PepperDash/hotfix/ssh-issues
Update PD Core version to fix SSH issue - DEV
2022-12-19 16:50:20 -07:00
Andrew Welker
99bc3f4f3e Merge branch 'development' into hotfix/ssh-issues 2022-12-19 16:21:47 -07:00
Trevor Payne
e8f773b2e6 Fix: removed references to pullup resistors in versiport digital outputs 2022-12-16 11:15:58 -05:00
Andrew Welker
e342bede11 Merge pull request #1046 from PepperDash/feature/Add-DinIo8
Feature/add din io8
2022-12-16 08:49:18 -07:00
Trevor Payne
81c779e595 Feat: Added Digital Outputs for Versiports 2022-12-16 10:18:58 -05:00
Trevor Payne
d980209bd8 Fixed Debug Statement to reflect proper device 2022-12-14 11:43:44 -06:00
Trevor Payne
c2a439d20d feat: Add DinIo8 2022-12-14 09:47:31 -06:00
Andrew Welker
52d945fca3 Merge pull request #1044 from PepperDash/hotfix/ssh-issues
Update PD Core version to fix SSH issues
2022-12-12 12:11:55 -07:00
Andrew Welker
0ef8fcfd27 chore: Update to PD Core 1.1.4 2022-12-12 11:42:16 -07:00
Andrew Welker
042416b470 chore: update PD Core version 2022-12-12 10:01:14 -07:00
Neil Dorin
84f2222c38 Merge pull request #1043 from PepperDash/hotfix/zoomroom-camera-selection
Send command to select camera by ID for Zoom Room - DEV
2022-12-09 09:21:20 -07:00
jdevito
966377ee2e Merge branch 'development' into hotfix/zoomroom-camera-selection 2022-12-09 09:39:56 -06:00
jdevito
3d27b0928f Merge pull request #1042 from PepperDash/hotfix/zoomroom-camera-selection
Send command to select camera by ID for Zoom Room
2022-12-09 09:39:33 -06:00
Andrew Welker
860182dbfc Merge branch 'main' into hotfix/zoomroom-camera-selection 2022-12-09 08:12:45 -07:00
Andrew Welker
f325ff7af0 Merge pull request #1041 from PepperDash/hotfix/occ-sensor-fixes
Prevent vacancy from shutting down the room when a call is active - DEV
2022-11-29 10:14:20 -07:00
Andrew Welker
58a5600ac6 Merge branch 'development' into hotfix/occ-sensor-fixes 2022-11-28 16:43:26 -07:00
Andrew Welker
efb6d3ef83 Merge pull request #1040 from PepperDash/hotfix/touchpanelBase
Get several fixes into dev
2022-11-28 16:43:08 -07:00
Andrew Welker
04477d62cc Merge branch 'development' into hotfix/touchpanelBase 2022-11-28 16:20:09 -07:00
Andrew Welker
668cbc430c Merge pull request #1038 from PepperDash/hotfix/occ-sensor-fixes
Prevent vacancy from shutting down the room when a call is active
2022-11-28 16:19:26 -07:00
Andrew Welker
e54de1f1cb Merge branch 'main' into hotfix/occ-sensor-fixes 2022-11-28 15:19:45 -07:00
Neil Dorin
f48b1a2de3 Merge pull request #1039 from PepperDash/hotfix/touchpanelBase
Fix issues with TouchpanelBase
2022-11-23 16:24:28 -07:00
Andrew Welker
8e57e7ec31 fix: add missing LoadSmartObjects call 2022-11-23 14:29:36 -07:00
Andrew Welker
1b43b44d19 fix: typo in TouchpanelBase constructor
The constructor was checking the wrong
variable, leading to it always being null
and failing to build the `EssentialsTouchpanelController`
class.
2022-11-23 13:15:41 -07:00
Andrew Welker
4306128474 refactor: fix abstract method 2022-11-21 10:45:25 -07:00
Andrew Welker
5263b16bb7 refactor: fix issues with log statments 2022-11-21 10:42:33 -07:00
Andrew Welker
a2b67798f3 refactor: add logging statements 2022-11-21 10:37:26 -07:00
Andrew Welker
1b43fba37e fix: add logic to prevent vacancy from triggering room off if room is in
a call
2022-11-21 10:28:08 -07:00
Andrew Welker
f262c1a3bb Merge pull request #1036 from PepperDash/hotfix/PD-core-update-for-vc4
Updates for VC-4
2022-11-16 11:05:40 -07:00
Andrew Welker
93ee695c57 Merge branch 'main' into hotfix/PD-core-update-for-vc4 2022-11-16 10:52:15 -07:00
Andrew Welker
ba0bae3c4e chore: update PD Core to 1.1.3 2022-11-16 10:51:48 -07:00
Trevor Payne
37a98d00af Merge pull request #1037 from PepperDash/hotfix/VideoCodec-ActiveCall-XSig
Fix error with updating call status XSigs
2022-11-14 10:25:28 -06:00
Trevor Payne
247827ac25 fix: UpdateCallStatusXsig() now properly refreshing calls 2022-11-14 10:10:22 -06:00
Andrew Welker
5e797db096 fix: add check for missing/empty roomId 2022-11-11 16:26:37 -07:00
Andrew Welker
57eeeec0fb Merge branch 'main' into hotfix/PD-core-update-for-vc4 2022-11-11 16:23:12 -07:00
Andrew Welker
db19da124c fix: set debug level to 2 on startup
Some plugins and devices are doing their own filtering based on the
debug level that's normally set using the `appdebug` console command.
On VC-4, there's no way to set that value. With this change, when
Essentials starts on a server, the debug level will be set to 2, so that
any of the messages that might be filtered based on the debug level
won't be filtered.
2022-11-11 14:37:46 -07:00
Andrew Welker
c07f52b06f feat: update VC-4 client to use correct RoomID 2022-11-10 12:51:04 -07:00
Trevor Payne
92e48a62a8 Merge pull request #1031 from PepperDash/feature/VideoCodec-XSig-Updates
Feature/video codec x sig updates
2022-11-09 13:47:23 -06:00
Andrew Welker
f3653039ca Merge branch 'development' into feature/VideoCodec-XSig-Updates 2022-11-09 11:56:06 -07:00
Andrew Welker
3b79c2c8c3 Merge pull request #1030 from PepperDash/hotfix/zoom-passcode-and-incoming-call-prompt-states-on-cancel
Hotfix/zoom passcode and incoming call prompt states on cancel
2022-11-09 11:55:57 -07:00
Andrew Welker
c9efa3cfaa Merge branch 'development' into hotfix/zoom-passcode-and-incoming-call-prompt-states-on-cancel 2022-11-09 11:26:11 -07:00
Andrew Welker
bd8a3de172 Merge pull request #1027 from PepperDash/hotfix/zoomroom-block-commands-on-incoming-call
Hotfix/zoomroom block commands on incoming call
2022-11-09 11:26:01 -07:00
Andrew Welker
7bc7e7ff4f Merge branch 'development' into hotfix/zoomroom-block-commands-on-incoming-call 2022-11-09 10:39:36 -07:00
Andrew Welker
afe0568177 Merge pull request #1025 from PepperDash/feature/Joinmap-Markdown
Feature/joinmap markdown
2022-11-09 10:36:24 -07:00
Andrew Welker
07c8c50c19 Merge branch 'development' into feature/Joinmap-Markdown 2022-11-09 10:01:59 -07:00
Andrew Welker
c34b4fc3a0 Merge pull request #1022 from PepperDash/hotfix/848-camera-preset-bridge-issue
Hotfix/848 camera preset bridge issue
2022-11-09 10:01:49 -07:00
Andrew Welker
b711548c3b Merge branch 'development' into hotfix/848-camera-preset-bridge-issue 2022-11-09 09:38:12 -07:00
Andrew Welker
906433ff8d Merge pull request #1006 from PepperDash/hotfix/SecretsManager-Add-Fix
fix: update secretsmanager loading mechanism
2022-11-09 09:38:00 -07:00
Neil Dorin
b6675477be Merge pull request #1029 from PepperDash/hotfix/zoom-passcode-and-incoming-call-prompt-states-on-cancel
Update Zoom polling/sending blocks for more scenarios
2022-11-09 09:27:07 -07:00
Andrew Welker
0b307ee40a Merge branch 'development' into hotfix/zoomroom-block-commands-on-incoming-call 2022-11-09 09:22:18 -07:00
Andrew Welker
f5d89e2067 Merge branch 'development' into feature/Joinmap-Markdown 2022-11-09 09:22:07 -07:00
Andrew Welker
c9a175031d Merge branch 'development' into hotfix/SecretsManager-Add-Fix 2022-11-09 09:21:56 -07:00
Andrew Welker
4fd01610c1 Merge branch 'development' into hotfix/848-camera-preset-bridge-issue 2022-11-09 09:21:39 -07:00
Trevor Payne
c19becc170 Merge branch 'main' into feature/VideoCodec-XSig-Updates 2022-11-08 11:44:09 -06:00
Andrew Welker
fc3840173e chore: Update PD Core version 2022-11-08 08:44:39 -07:00
Andrew Welker
ce51a62d97 chore: update PD Core version 2022-11-04 14:01:11 -06:00
Andrew Welker
2be42f88bc chore: update PD Core version
In order to fix issues with debug file location for VC-4, the PD Core version needs to be updated
2022-11-04 09:48:17 -06:00
Trevor Payne
60afe203dd fix: XSig Fixes 2022-11-02 09:18:20 -05:00
jdevito
6f9a9ee255 fix: moved setting set in event before null check 2022-10-28 16:47:43 -05:00
jdevito
a09212417c fix: removed property sets as recommended in discussion; removed 'if' statements before property sets in leave and end call methods 2022-10-28 16:20:49 -05:00
jdevito
4d6da37c60 fix: added additional evaluations for prompt property tracking and set/reset to handled unknown user scenarios 2022-10-28 08:38:16 -05:00
Andrew Welker
95627df1a6 Merge pull request #1026 from PepperDash/hotfix/zoomroom-block-commands-on-incoming-call
fix(essentials): Block all commands to ZoomRoom on incoming call
2022-10-25 13:40:32 -06:00
Neil Dorin
bef07fe41b fix(essentials): Block all commands to ZoomRoom on incoming call 2022-10-25 10:30:02 -06:00
Trevor Payne
99e1ec3b3b Merge pull request #1020 from PepperDash/hotfix/xSigUpdateActiveCall-Fix
Hotfix/x sig update active call fix
2022-10-24 12:47:13 -05:00
Trevor Payne
e44e7c976f Merge branch 'development' into feature/Joinmap-Markdown 2022-10-21 16:27:44 -05:00
Trevor Payne
fea3189a18 refactor: moved markdown method inside join data
feat: proper error handling
2022-10-21 16:20:14 -05:00
Trevor Payne
578754de85 feat: Added new folder program<x>/joinmaps
feat: added new console command to write markdown for joinmap data and save to file
2022-10-20 13:09:32 -05:00
Andrew Welker
4903232c10 Merge branch 'development' into hotfix/xSigUpdateActiveCall-Fix 2022-10-20 11:18:13 -06:00
Andrew Welker
83d2497264 Merge pull request #1021 from PepperDash/hotfix/848-camera-preset-bridge-issue
fix: max number of presets now uses join span rather than join start.
2022-10-20 11:17:39 -06:00
Andrew Welker
50f5145a89 Merge branch 'main' into hotfix/848-camera-preset-bridge-issue 2022-10-20 10:58:10 -06:00
Neil Dorin
969abcc8b6 Merge pull request #1024 from PepperDash/hotfix/zoomrooms-passcode-required-prohibits-polling
fix: added bool property tracking if meeting is require, added poll m…
2022-10-20 10:46:49 -06:00
Neil Dorin
c136943c3a Merge branch 'development' into hotfix/zoomrooms-passcode-required-prohibits-polling 2022-10-20 10:30:40 -06:00
Neil Dorin
a734a869c1 Merge pull request #1023 from PepperDash/hotfix/zoomrooms-passcode-required-prohibits-polling
fix: added bool property tracking if meeting is require, added poll m…
2022-10-20 10:30:14 -06:00
Neil Dorin
c6495577e7 Merge branch 'main' into hotfix/zoomrooms-passcode-required-prohibits-polling 2022-10-20 10:15:46 -06:00
jdevito
5359604098 fix: added bool property tracking if meeting is require, added poll method and updated GetBookings to reference bool property that prohibits polling when meeting password is required 2022-10-20 11:11:07 -05:00
Jason Alborough
70d2633eb0 fix: max number of presets now uses join span rather than join start. 2022-10-20 09:52:58 -04:00
Andrew Welker
58aa9dae08 Merge branch 'development' into hotfix/xSigUpdateActiveCall-Fix 2022-10-18 10:21:30 -06:00
Andrew Welker
6715a680cc Merge pull request #1019 from PepperDash/hotfix/xSigUpdateActiveCall-Fix
fix: update xSig Method for active call status
2022-10-18 10:21:11 -06:00
Trevor Payne
f3fc0f2b26 fix: update xSig Method for active call status 2022-10-18 10:51:24 -05:00
Neil Dorin
330bb2d002 fix(essentials): #1017 -Send command to select camera by ID 2022-10-13 11:13:17 -06:00
Neil Dorin
c0436b1230 Merge branch 'development' into hotfix/SecretsManager-Add-Fix 2022-10-06 12:45:15 -06:00
Neil Dorin
26b968463b Merge pull request #1015 from PepperDash/hotfix/shade-interface-updates
fix(essentials): Updates to shade interfaces to clarify functionality
2022-10-06 12:44:21 -06:00
Andrew Welker
d33b89f232 Merge branch 'main' into hotfix/shade-interface-updates 2022-10-06 12:29:27 -06:00
Andrew Welker
10d77ac006 Merge pull request #1011 from PepperDash/hotfix/zoomroom-default-layout
Hotfix/zoomroom default layout
2022-10-06 11:06:30 -06:00
Andrew Welker
c19ab76a4c Merge pull request #1013 from PepperDash/hotfix/VideoCodecBase-Xsig-Fixes
Hotfix/video codec base xsig fixes
2022-10-06 11:02:03 -06:00
Neil Dorin
040c57b5e1 fix(essentials): Updates to shade interfaces to clarify functionality 2022-10-06 10:05:44 -06:00
Trevor Payne
d6864bf214 Merge branch 'hotfix/VideoCodecBase-Xsig-Fixes' of https://github.com/PepperDash/Essentials into hotfix/VideoCodecBase-Xsig-Fixes 2022-10-06 00:38:15 -05:00
Trevor Payne
62275890cb style: changed tracking variable in UpdateCallStatusXsig 2022-10-06 00:38:02 -05:00
Trevor Payne
2a6b845fde Merge branch 'main' into hotfix/VideoCodecBase-Xsig-Fixes 2022-10-05 16:51:11 -05:00
Trevor Payne
4fb2d6d755 fix: updated XSig methods in VideoCodecBase 2022-10-05 16:13:53 -05:00
Neil Dorin
5994704fbd Merge pull request #1010 from PepperDash/hotfix/zoomroom-default-layout
Hotfix/zoomroom default layout
2022-09-30 08:27:03 -06:00
Neil Dorin
ca1cbb6e05 fix(essentials): Resolves null ref in LinkZoomRoomToApi 2022-09-29 14:11:41 -06:00
Neil Dorin
f82b7f8f12 refactor(essentials): cleans up some args names for clarity 2022-09-29 13:33:15 -06:00
Neil Dorin
dbd77f5f9f fix(essentials): Switch to SetSigTrueAction for a few joins 2022-09-29 12:35:05 -06:00
Neil Dorin
55031d16af docs(essentials): Add join name to printjoinmap and update description on StartMeetingNow join 2022-09-29 12:33:42 -06:00
Neil Dorin
4938071f70 fix(essentials): Updates the func to return whether sharing content 2022-09-29 11:22:13 -06:00
Neil Dorin
3670bde7cf fix(essentials): Adds extra private field to trigger OnShareInfoChanged 2022-09-29 10:53:55 -06:00
Neil Dorin
4deb9a0828 fix(essentials): Updates to deal with sharing status and adds a property to notify if meeting can be recorded 2022-09-28 14:55:14 -06:00
Neil Dorin
a524b1607d fix(essentials): Updates to deal with layouts and default layout for ZoomRoom 2022-09-28 12:28:37 -06:00
Trevor Payne
155f511ce2 Merge branch 'hotfix/SecretsManager-Add-Fix' of https://github.com/PepperDash/Essentials into hotfix/SecretsManager-Add-Fix 2022-09-27 13:04:54 -05:00
Trevor Payne
21b09c593a Merge branch 'development' into hotfix/SecretsManager-Add-Fix 2022-09-27 13:03:47 -05:00
Trevor Payne
cdeca09855 Merge branch 'development' into hotfix/SecretsManager-Add-Fix 2022-09-27 13:03:25 -05:00
Andrew Welker
93435b60b5 Merge pull request #1005 from PepperDash/release/1.11.0
Release/1.11.0
2022-09-26 14:48:51 -06:00
Neil Dorin
2daf3c0328 Merge pull request #1004 from PepperDash/release/1.11.0
1.11.0
2022-09-26 14:13:50 -06:00
Andrew Welker
eaef8ea616 Merge branch 'main' into release/1.11.0 2022-09-26 11:52:43 -06:00
Andrew Welker
b67eb6325b Merge pull request #1003 from PepperDash/hotfix/add-zoomroom-share-info
Hotfix/add zoomroom share info
2022-09-26 08:40:36 -06:00
Andrew Welker
38cb86218c Merge branch 'development' into hotfix/add-zoomroom-share-info 2022-09-26 08:29:05 -06:00
Andrew Welker
edddf295fe Merge pull request #1002 from PepperDash/hotfix/add-zoomroom-share-info
Various Zoom Room updates
2022-09-23 14:53:22 -06:00
Neil Dorin
05ec0ebac3 fix(essentials): Adds ability to dial up to 10 calls from SIMPL bridge 2022-09-23 12:27:55 -06:00
Neil Dorin
c3d07fe4fd fix(essentials): Adds EndAllCalls to CancelJoinAttempt action 2022-09-23 08:28:32 -06:00
Neil Dorin
eae089cdf5 fix(essentials): updates to password prompt logic 2022-09-22 15:38:11 -06:00
Neil Dorin
b48859d202 adds missing .csproj update 2022-09-22 13:06:00 -06:00
Neil Dorin
bda46eb1b9 fix(essentials): adds cancel method for password prompt and adds wireless share instructions 2022-09-22 13:05:09 -06:00
Trevor Payne
47c24a237e fix: update secretsmanager loading mechanism 2022-09-22 12:09:26 -04:00
Neil Dorin
ee735388bb fix(essentials): reworks SIMPL bridging logic for hiding password prompt 2022-09-15 12:44:17 -06:00
Andrew Welker
77f202b9f4 Merge pull request #1000 from PepperDash/hotfix/zoom-room-content-sharing-fb
fix(essentials): Fixes SharingSourceFeedback value to actually read F…
2022-09-14 17:00:09 -06:00
Neil Dorin
939afb7aae fix(essentials): Fixes SharingSourceFeedback value to actually read FB state instead of which on screen instructions are shown 2022-09-14 16:40:26 -06:00
Andrew Welker
4a98b58b60 Merge pull request #997 from PepperDash/hotfix/zoom-passcode-prompt
Update Zoom passcode bridging logic
2022-09-09 10:39:02 -06:00
Andrew Welker
2bf9336712 Merge branch 'main' into hotfix/zoom-passcode-prompt 2022-09-09 10:24:14 -06:00
Andrew Welker
c0c67f6c15 Merge pull request #996 from PepperDash/hotfix/zoom-room-privacy-mute-notincall
Hotfix/zoom room privacy mute notincall
2022-09-08 16:08:13 -06:00
Andrew Welker
eb3922aa43 Merge branch 'development' into hotfix/zoom-room-privacy-mute-notincall 2022-09-08 15:08:44 -06:00
Andrew Welker
598886dfd4 Merge pull request #995 from PepperDash/hotfix/zoom-room-privacy-mute-notincall
Set Zoom Room privacy/mic mute to report unmuted when not in a meeting
2022-09-08 15:08:32 -06:00
Neil Dorin
215cf6696e fix(essentials): Set not in call state to report as unmuted 2022-09-08 14:26:18 -06:00
Neil Dorin
c557400f38 fix(essentials): updates ZoomRoom mute state to report muted when not in call 2022-09-08 14:26:18 -06:00
Trevor Payne
49a96d2632 Merge pull request #993 from PepperDash/feature/Cisco-RoomOS-Codec-Support-Cleanup
Various fixes for VideoCodecBase
2022-09-06 17:36:06 -05:00
Trevor Payne
ccf7acd53d feat: update bridging, device factory, and interfaces
In order to support the way some Smart Objects work, a clear
directory join was needed in order to allow for clearing a
selection in certain circumstances.

In order to support finer-grained dependencies while
developing plugins, the Development Device Factory was added.
2022-09-06 17:16:27 -05:00
jdevito
f1590aeec8 fix: added 'CancelPasswordPrompt' join, updated linkToZoomApi 2022-09-06 14:10:21 -05:00
jdevito
f1d1ce9722 fix: added OnPasswordRequired event call in SubmitPassword method to clear popup when bridged 2022-09-06 14:04:19 -05:00
Neil Dorin
edd55d0349 Merge pull request #992 from PepperDash/feature/touchpanel-plugins
Add TouchpanelBase class and initial implementation
2022-09-02 15:15:20 -06:00
Andrew Welker
384c4c2781 Merge branch 'feature/touchpanel-plugins' of https://github.com/PepperDash/Essentials into feature/touchpanel-plugins 2022-09-02 15:00:12 -06:00
Andrew Welker
9b2611be02 refactor: add error handling for cases where type isn't found 2022-09-02 15:00:00 -06:00
Andrew Welker
26bd49aa85 Merge branch 'development' into feature/touchpanel-plugins 2022-09-02 14:45:06 -06:00
Andrew Welker
1b9f16ea74 fix: add missing event registration 2022-09-02 14:44:15 -06:00
Andrew Welker
88a16b577b refactor: update constructors for touchpanel controller and base class 2022-09-02 14:35:06 -06:00
Andrew Welker
b4ab0c1c32 Merge pull request #991 from PepperDash/hotfix/essentials-cooling-routing
Hotfix/essentials cooling routing
2022-09-02 13:56:05 -06:00
Andrew Welker
d01be57f81 feat: add TouchpanelBase class and initial implementation 2022-09-02 13:54:34 -06:00
Andrew Welker
5ba7abb59b Merge branch 'development' into hotfix/essentials-cooling-routing 2022-09-02 11:49:06 -06:00
Andrew Welker
f5a352cf08 Merge pull request #990 from PepperDash/hotfix/essentials-cooling-routing
Magic Routing holds last requested route until cooling is complete
2022-09-02 11:37:46 -06:00
Neil Dorin
c4a23e0887 feat(essentials): Adds RoomUiBehaviorConfig for disabling activity buttons 2022-09-02 11:19:18 -06:00
Andrew Welker
2622e68afc Merge pull request #957 from PepperDash/feature/dmps-dm-fixes
Feature/dmps dm fixes
2022-09-02 11:00:16 -06:00
Andrew Welker
7fe2d04d31 fix: add removal of RouteRequest when calling ReleaseRoute 2022-09-01 12:29:19 -06:00
Andrew Welker
358f44cfe5 refactor: remove completed request from dictionary 2022-09-01 11:57:40 -06:00
Andrew Welker
d7cccc0709 feat: add cooldown logic to Magic Routing
In some cases, a route can be requested while a sink is cooling down.
In those cases, the routing logic should keep track of requests for a
destination and wait until cooling is complete to request the new
route.
2022-09-01 11:47:52 -06:00
Andrew Welker
72086b57b3 Merge branch 'development' into feature/dmps-dm-fixes 2022-08-31 15:06:34 -06:00
Andrew Welker
f04b93d5e9 Merge pull request #989 from PepperDash/feature/cen-io-ir-104
Feature/cen io ir 104
2022-08-31 15:06:24 -06:00
Andrew Welker
18c52ca199 Merge branch 'development' into feature/dmps-dm-fixes 2022-08-31 14:49:56 -06:00
Andrew Welker
1dcafff8fb Merge branch 'development' into feature/cen-io-ir-104 2022-08-31 14:49:13 -06:00
Andrew Welker
81b1117310 Merge pull request #988 from PepperDash/feature/cen-io-ir-104
Add Support for CEN-IO devices
2022-08-31 14:47:58 -06:00
jdevito
fb689c4484 fix: updated CEN-IO classes inheriting from EssentialsDevice to CrestronGenericBaseDevice to resolve activation issues 2022-08-31 14:43:58 -05:00
jdevito
40cb1b0fcf Merge remote-tracking branch 'origin/hotfix/huddle-room-interfaces' into feature/cen-io-ir-104 2022-08-31 11:55:15 -05:00
Jason DeVito
4574941288 fix: updated debug statement for DinCenCnController class referencing building a temp sensor device 2022-08-30 22:11:33 -05:00
Jason DeVito
122abc56e5 fix: added null checks in BuildDevice with debug statements if null 2022-08-30 22:02:47 -05:00
Jason DeVito
074ee190ad feat: added cen-io-ir-104 device and factory 2022-08-30 21:53:41 -05:00
Andrew Welker
68a0157fbe fix: add missing interface 2022-08-30 13:57:53 -06:00
Alex Johnson
0376943dac Reworks the creation process for DM transmitters 2022-08-20 15:18:39 -04:00
Andrew Welker
62abbdf5e9 Merge pull request #981 from PepperDash/hotfix/zoomroom-bridge-updates
Hotfix/zoomroom bridge updates
2022-08-18 08:50:17 -06:00
Jason DeVito
12248c6393 fix: removed extra debug statements 2022-08-12 17:36:38 -05:00
Jason DeVito
139ecc3e58 fix: (wip) updated VideoCodecBase LinkToApis to resolve issue #983 with call status and directory not updating wtih bridge online status change 2022-08-12 17:32:54 -05:00
jdevito
afa0a4cac2 Merge branch 'development' into hotfix/zoomroom-bridge-updates 2022-08-12 16:04:40 -05:00
Alex Johnson
ed335cc9ae Fixes for offline feedback for DM endpoints that don't provide offline feedback in the hardware definition. Adds offline and name feedback to joinMap for these devices. 2022-08-12 09:26:09 -04:00
Alex Johnson
5d51570018 Merge branch 'development' into feature/dmps-dm-fixes 2022-08-12 09:07:49 -04:00
Andrew Welker
e5393deea8 Merge pull request #980 from PepperDash/hotfix/zoomroom-bridge-updates
Hotfix/zoomroom bridge updates
2022-08-10 16:28:16 -06:00
Jason DeVito
c446c3a976 fix: updates to resolve directory display issues on touch panel when bridged 2022-08-10 17:12:30 -05:00
Jason DeVito
49e44ec850 fix: updated VideoCodecBase UpdateDirectoryXSig to handle directory results that are greater than 1023, XSig maximimum index 2022-08-10 15:49:41 -05:00
Andrew Welker
7298b9b767 Merge pull request #977 from PepperDash/hotfix/fix-lightingScene-scene-select-index
Hotfix/fix lighting scene scene select index
2022-08-08 15:49:19 -06:00
Andrew Welker
5a8914a33f Merge branch 'development' into hotfix/fix-lightingScene-scene-select-index 2022-08-08 13:34:27 -06:00
Trevor Payne
dccab58a28 Merge pull request #969 from PepperDash/bugfix/CrestronDatastor-Errors
Bugfix/crestron datastor errors
2022-07-19 09:54:53 -05:00
Andrew Welker
19d29a03c8 Merge branch 'development' into bugfix/CrestronDatastor-Errors 2022-07-19 08:33:47 -06:00
Andrew Welker
41bc6a9cd4 Merge pull request #967 from PepperDash/feature/VideoCodec-Improvements
Feature/video codec improvements
2022-07-19 08:33:30 -06:00
Trevor Payne
051d50e8c9 Merge branch 'bugfix/CrestronDatastor-Errors' of https://github.com/PepperDash/Essentials into bugfix/CrestronDatastor-Errors 2022-07-18 15:10:12 -05:00
Trevor Payne
16af75ae0d fix: updated erroneous console responses for Secrets Providers
refactor: updated method by which the Factories assess secret objects

refactor: updated 'SecretsManager' console responses

feat: added 'secretproviderlist' console command

feat: added 'secretproviderinfo' console command

feat: added 'CrestronGlobalSecretsProvider'

feat: Added 'Description' property to 'ISecretProvider'

feat: added 'TestSecret' method to 'ISecretProvider'

docs: added xml comments to 'ISecretProvider'

docs: added xml comments to 'ISecret'

refactor: cleaned up crestron default secrets provider classes

refactor: moved 'CrestronSecret' to its own class file

refactor: overhauled all secrets-related console commands

resolves #968
2022-07-18 15:07:19 -05:00
Trevor Payne
4037fad26b fix: updated erroneous console responses for Secrets Providers
refactor: updated method by which the Factories assess secret objects

refactor: updated 'SecretsManager' console responses

feat: added 'secretproviderlist' console command

feat: added 'secretproviderinfo' console command

feat: added 'CrestronGlobalSecretsProvider'

feat: Added 'Description' property to 'ISecretProvider'

feat: added 'TestSecret' method to 'ISecretProvider'

docs: added xml comments to 'ISecretProvider'

docs: added xml comments to 'ISecret'

refactor: cleaned up crestron default secrets provider classes

refactor: moved 'CrestronSecret' to its own class file

refactor: overhauled all secrets-related console commands
2022-07-18 15:05:08 -05:00
Trevor Payne
5a4cc2fd39 fix:console commands for Secrets Management Modified 2022-07-15 17:40:48 -05:00
Trevor Payne
04e8508c0c fix: requested changes for PR #967 2022-07-15 11:38:19 -05:00
Trevor Payne
cbab051c11 Fixed Merge Issue
Adjusts #966
2022-07-12 15:53:59 -05:00
Trevor Payne
9c8bb66c5e [Fix] - Updated IHasCodecLayoutsAvailable setters
[Adjusts] #966
2022-07-12 15:48:53 -05:00
Trevor Payne
96ec2cbe49 [Fix] - Updated IHasCodecLayoutsAvailable setters
[Adjusts] #966
2022-07-12 15:38:48 -05:00
Trevor Payne
9ecaec5584 [fix] slight change to move CodecCommandWithLabel into the VideoCodec namespace and modify the IHasCodecLayoutsAvailable interface to utilize this class
Modifies #966
2022-07-12 15:02:22 -05:00
Trevor Payne
b505ad467b [feature] added IHasCodecLayoutsAvailable interface and associated bridge linking methods
Modifies #966
2022-07-12 12:34:28 -05:00
Trevor Payne
d8ac302f1c [feature] - Create and Implement IConvertiblePreset within the VideoCodec and the VideoCodec.Cisco namespaces
RESOLVES #966
2022-07-11 17:30:51 -05:00
Alex Johnson
712d38011c Merge branch 'development' into feature/dmps-dm-fixes 2022-06-27 13:30:24 -04:00
Alex Johnson
d849e4185c Fixes clear audio route on DMPS3-4K-150. Fixes output names on join map for DMPS3-4K-150 2022-06-27 09:35:38 -04:00
Neil Dorin
c3818b8bf2 Merge pull request #964 from PepperDash/feature/handle-prs
Feature/handle prs
2022-06-22 09:55:55 -06:00
Neil Dorin
bbb31aea23 Merge pull request #959 from ciasia/bugfix/958-SubpageRefernceList-Get__OutputSig
GetStringOutputSig and GetUShortOutputSig return
2022-06-22 09:15:01 -06:00
Andrew Welker
4a405804c8 Merge pull request #960 from PepperDash/feature/iBasicVolumewFB-better-pull
Fix IBasicVolumeControls
2022-06-21 17:29:31 -05:00
jta
38c4a540a9 fix for IBasicVolumeWithFeedback
fix: for a change that split the interface but could break backwards compatibility #955
2022-06-21 18:05:23 -04:00
jta
4c9a470885 Fix IBasicVolumeControls
fix: revert a change that split the interface but could break backwards compatibility #955
2022-06-21 17:55:18 -04:00
Andrew Welker
be5158d29e Merge pull request #947 from PepperDash/feature/pdu-interface-joinmap
Added new Interfaces and JoinMap for PDUs
2022-06-21 15:40:54 -05:00
Andrew Welker
8ce390d650 Merge branch 'development' into feature/pdu-interface-joinmap 2022-06-21 13:42:17 -05:00
Neil Dorin
05066dc1ea Merge pull request #953 from PepperDash/hotfix/c2nio-factory-reference-update
Hotfix/c2nio factory reference update
2022-06-21 12:27:04 -06:00
Andrew Welker
70a78b540d Merge branch 'development' into feature/pdu-interface-joinmap 2022-06-21 13:12:50 -05:00
Neil Dorin
c56caff1cb Merge branch 'development' into feature/dmps-dm-fixes 2022-06-21 12:12:35 -06:00
Andrew Welker
5e22ca9c59 Merge branch 'development' into hotfix/c2nio-factory-reference-update 2022-06-21 13:12:02 -05:00
Andrew Welker
5131e73567 Merge pull request #944 from PepperDash/hotfix/zoom-recording-prompt
Hotfix/zoom recording prompt
2022-06-21 13:11:45 -05:00
Neil Dorin
e02c267988 Merge branch 'development' into hotfix/zoom-recording-prompt 2022-06-21 11:47:33 -06:00
Alex Johnson
53c9f9e664 Fixes issue where sometimes clear route doesn't work on DMPS3 2022-06-17 14:42:51 -04:00
Rodney Driscoll
794ba7e6dd GetStringOutputSig and GetUShortOutputSig return 2022-06-17 09:38:16 +10:00
Alex Johnson
5b94d89bc3 Improvements for DMPS3-4K-150 types 2022-06-15 20:26:32 -04:00
Alex Johnson
6dbdd0587d Reworks audio routing on DMPS-4K units. 2022-06-15 08:49:52 -04:00
Alex Johnson
1a5d4896e1 Fixes online feedback for DM endpoints that are attached to a 3 series DM chassis or a DMPS-4K unit. 2022-06-14 10:43:29 -04:00
Alex Johnson
50e9a7935f Adds HD-MD-8xn switcher type support 2022-06-14 10:25:06 -04:00
Alex Johnson
03e4c913ac Adds HD-MD-8xn switcher type support 2022-06-14 10:24:19 -04:00
Alex Johnson
b26e1b97aa Removes redundant check for DMPS-4K type. Property exists elsewhere 2022-06-14 10:23:51 -04:00
Alex Johnson
60b6cea697 Adds digital audio output volume control for DMPS to bridge 2022-06-14 10:13:02 -04:00
Alex Johnson
dfc0915fe0 Adds DM switcher name to bridge 2022-06-14 09:56:40 -04:00
Alex Johnson
96e3d52b95 Switch DMPS units to only wait until devices are registered before continuing. No need to wait for devices to be activated. 2022-06-14 09:43:59 -04:00
Trevor Payne
1cc37b7521 feature:Converted PduOutlets Dictionary to ReadOnlyDictionary
feature:Removed redundant OutletCount property
2022-06-02 11:17:54 -05:00
Trevor Payne
86dfc395ec Rename IHasPowerReboot to IHasPowerCycle
Update naming scheme to Cycle from Reboot
2022-05-31 17:48:18 -05:00
Trevor Payne
05f3a7eb2c UpdateJoinmap Names 2022-05-31 17:46:13 -05:00
Trevor Payne
20beeb076a add new interfaces for implementing PDUs
added basic join map
2022-05-31 17:19:56 -05:00
Andrew Welker
a74753d4a3 Merge pull request #923 from PepperDash/feature/fileio
feature: add static fileio class to read and write files
2022-05-03 15:28:09 -06:00
Andrew Welker
768a93d44d Merge branch 'development' into feature/fileio 2022-05-02 13:40:30 -06:00
Andrew Welker
46cb10f452 Merge pull request #937 from PepperDash/hotfix/zoomroom-duplicate-passwordRequired-eventhandlers
Hotfix/zoomroom duplicate password required eventhandlers
2022-05-02 13:40:12 -06:00
Andrew Welker
5386f0fffb Merge branch 'development' into feature/fileio 2022-04-28 10:07:48 -06:00
Andrew Welker
ad3ae0de69 Merge branch 'development' into hotfix/zoomroom-duplicate-passwordRequired-eventhandlers 2022-04-28 10:07:24 -06:00
Andrew Welker
892167d236 Merge pull request #938 from PepperDash/release/1.10.0
Release/1.10.0
2022-04-28 10:07:06 -06:00
Andrew Welker
e843098ac3 Merge branch 'development' into release/1.10.0 2022-04-28 09:05:25 -06:00
Jason T Alborough
1566e04edf Merge branch 'development' into feature/fileio 2022-04-20 14:20:05 -04:00
Jason Alborough
f902a57f60 feature: add fileLock for reads 2022-04-19 15:19:27 -04:00
Jason Alborough
33c7038d99 feature: write file is now on a low priority thread.
feature: add asynchronous read file methods and event
2022-03-24 17:50:34 -04:00
Trevor Payne
7f36a00813 Merge pull request #926 from PepperDash/feature/add-room-factories
feat: add ability to build rooms with extant device factory
2022-03-23 15:51:20 -05:00
Trevor Payne
c4843d68f4 feat: add ability to build rooms with extant device factory
RESOLVES #925
2022-03-23 15:28:25 -05:00
Jason Alborough
7e8d88c3af fix: fix method name in test 2022-03-21 18:32:34 -04:00
Jason Alborough
c539c79135 fix: fix case on \user\ folder path for four series support. 2022-03-21 17:08:36 -04:00
Jason Alborough
281b6f065f fix: remove method FileExsists
fix: fixed casing in debug statement
fix: changed the method name to ReadDataFromFile.
feature: added an overload ReadDataFromFile(string)
2022-03-21 17:06:18 -04:00
Jason Alborough
acfbefca00 feature: add static fileio class to read and write files 2022-03-15 09:33:06 -04:00
Trevor Payne
397c0f250b Merge pull request #916 from PepperDash/feature/split-volume-interfaces-for-composition
Feature/split volume interfaces for composition
2022-03-14 23:17:26 -05:00
Trevor Payne
a1dce1bb17 Merge branch 'development' into feature/split-volume-interfaces-for-composition 2022-03-14 22:58:13 -05:00
Nick Genovese
15aacbd8c8 Merge pull request #910 from PepperDash/bugfix/lightingBase-sceneIndex
Updates to forEach loop sceneIndex to include local sceneIndex context
2022-03-14 20:32:42 -04:00
Nick Genovese
34a695ba95 feat (essentials): fixed a few build issues with the new volume interfaces 2022-03-14 19:51:55 -04:00
Nick Genovese
0ab1ece445 feat (essentials): split up volume interfaces for better composition
fix (essentials): fixed a few misc devices that are probably deprecated anyhow
2022-03-14 19:26:50 -04:00
Jonathan Arndt
747c68bd1e Updates to forEach loop sceneIndex to include local sceneIndex context 2022-02-16 22:17:45 -08:00
171 changed files with 13902 additions and 4497 deletions

2
.gitignore vendored
View File

@@ -389,3 +389,5 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/PepperDash_Essentials_Interfaces.csproj
.DS_Store
._.DS_Store

View File

@@ -91,8 +91,8 @@ we receive and the availability of resources to evaluate contributions, we antic
project remains dynamic and relevant. This may affect our responsiveness and ability to accept pull requests
quickly. This does not mean we are ignoring them.
- Not all innovative ideas need to be accepted as pull requests into this GitHub project to be valuable to the community.
There may be times when we recommend that you just share your code for some enhancement to Ghidra from your own
repository. As we identify and recognize extensions that are of general interest to the reverse engineering community, we
There may be times when we recommend that you just share your code for some enhancement to Essentials from your own
repository. As we identify and recognize extensions that are of general interest to Essentials, we
may seek to incorporate them with our baseline.
## Legal

View File

@@ -55,7 +55,7 @@ namespace PepperDash.Essentials
return null;
}
// DSP format: deviceKey--levelName, biampTesira-1--master
// DSP/DMPS format: deviceKey--levelName, biampTesira-1--master
match = Regex.Match(DeviceKey, @"([-_\w]+)--(.+)");
if (match.Success)
{
@@ -67,6 +67,27 @@ namespace PepperDash.Essentials
if (dsp.LevelControlPoints.ContainsKey(levelTag)) // should always...
return dsp.LevelControlPoints[levelTag];
}
var dmps = DeviceManager.GetDeviceForKey(devKey) as DmpsAudioOutputController;
if (dmps != null)
{
var levelTag = match.Groups[2].Value;
switch (levelTag)
{
case "master":
return dmps.MasterVolumeLevel;
case "source":
return dmps.SourceVolumeLevel;
case "micsmaster":
return dmps.MicsMasterVolumeLevel;
case "codec1":
return dmps.Codec1VolumeLevel;
case "codec2":
return dmps.Codec2VolumeLevel;
default:
return dmps.MasterVolumeLevel;
}
}
// No volume for some reason. We have failed as developers
return null;
}

View File

@@ -70,7 +70,7 @@ namespace PepperDash.Essentials.Bridges
catch (NullReferenceException)
{
Debug.ConsoleWithLog(0, this,
"Please update the bridge config to use EiscBridgeAdvanced with this device: {0}", device.Key);
"Please update the bridge config to use eiscApiAdvanced with this device: {0}", device.Key);
}
}
Debug.Console(1, this, "Devices Linked.");

View File

@@ -13,6 +13,7 @@ using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Fusion;
using PepperDash.Essentials.Core.Web;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion;
@@ -46,28 +47,29 @@ namespace PepperDash.Essentials
/// </summary>
public override void InitializeSystem()
{
_startTimer = new CTimer(StartSystem,StartupTime);
// If the control system is a DMPS type, we need to wait to exit this method until all devices have had time to activate
// to allow any HD-BaseT DM endpoints to register first.
if (Global.ControlSystemIsDmpsType)
bool preventInitializationComplete = Global.ControlSystemIsDmpsType;
if (preventInitializationComplete)
{
Debug.Console(2, "******************* InitializeSystem() Entering **********************");
_initializeEvent = new CEvent();
DeviceManager.AllDevicesActivated += (o, a) =>
Debug.Console(1, "******************* InitializeSystem() Entering **********************");
_startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime);
_initializeEvent = new CEvent(true, false);
DeviceManager.AllDevicesRegistered += (o, a) =>
{
_initializeEvent.Set();
Debug.Console(2, "******************* InitializeSystem() Exiting **********************");
};
_initializeEvent.Wait(30000);
Debug.Console(1, "******************* InitializeSystem() Exiting **********************");
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
else
{
_startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime);
}
}
private void StartSystem(object obj)
private void StartSystem(object preventInitialization)
{
DeterminePlatform();
@@ -79,36 +81,41 @@ namespace PepperDash.Essentials
CrestronConsole.AddNewConsoleCommand(PluginLoader.ReportAssemblyVersions, "reportversions", "Reports the versions of the loaded assemblies", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(PepperDash.Essentials.Core.DeviceFactory.GetDeviceFactoryTypes, "gettypes", "Gets the device types that can be built. Accepts a filter string.", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(Core.DeviceFactory.GetDeviceFactoryTypes, "gettypes", "Gets the device types that can be built. Accepts a filter string.", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(BridgeHelper.PrintJoinMap, "getjoinmap", "map(s) for bridge or device on bridge [brKey [devKey]]", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "CONSOLE MESSAGE: {0}", s);
}, "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(BridgeHelper.JoinmapMarkdown, "getjoinmapmarkdown"
, "generate markdown of map(s) for bridge or device on bridge [brKey [devKey]]", 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\n", tl);
CrestronConsole.ConsoleCommandResponse(" {0}{1}", tl, CrestronEnvironment.NewLine);
},
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(s =>
{
CrestronConsole.ConsoleCommandResponse
("Current running configuration. This is the merged system and template configuration");
("Current running configuration. This is the merged system and template configuration" + CrestronEnvironment.NewLine);
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\n" +
"System URL: {0}\r\n" +
"Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
}, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.ConsoleCommandResponse(
"This system can be found at the following URLs:{2}" +
"System URL: {0}{2}" +
"Template URL: {1}{2}",
ConfigReader.ConfigObject.SystemUrl,
ConfigReader.ConfigObject.TemplateUrl,
CrestronEnvironment.NewLine),
"portalinfo",
"Shows portal URLS from configuration",
ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(DeviceManager.GetRoutingPorts,
@@ -120,7 +127,10 @@ namespace PepperDash.Essentials
return;
}
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
if (!(bool)preventInitialization)
{
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
}
/// <summary>
@@ -195,6 +205,8 @@ namespace PepperDash.Essentials
}
else // Handles Linux OS (Virtual Control)
{
Debug.SetDebugLevel(2);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on Virtual Control Server", Global.AssemblyVersion);
// Set path to User/
@@ -296,6 +308,10 @@ namespace PepperDash.Essentials
if (!Directory.Exists(pluginDir))
Directory.Create(pluginDir);
var joinmapDir = Global.FilePathPrefix + "joinmaps";
if(!Directory.Exists(joinmapDir))
Directory.Create(joinmapDir);
return configExists;
}
@@ -343,6 +359,7 @@ namespace PepperDash.Essentials
// Build the processor wrapper class
DeviceManager.AddDevice(new PepperDash.Essentials.Core.Devices.CrestronProcessor("processor"));
DeviceManager.AddDevice(new EssemtialsWebApi("essentialsWebApi","Essentials Web API"));
// Add global System Monitor device
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
@@ -384,20 +401,21 @@ namespace PepperDash.Essentials
}
else if (this.ControllerPrompt.IndexOf("mpc3", StringComparison.OrdinalIgnoreCase) > -1)
{
Debug.Console(2, "MPC3 processor type detected. Adding Mpc3TouchpanelController.");
Debug.Console(2, "MPC3 processor type detected. Adding Mpc3TouchpanelController.");
var butToken = devConf.Properties["buttons"];
if (butToken != null)
{
var buttons = butToken.ToObject<Dictionary<string, Essentials.Core.Touchpanels.KeypadButton>>();
var tpController = new Essentials.Core.Touchpanels.Mpc3TouchpanelController(devConf.Key, devConf.Name, Global.ControlSystem, buttons);
DeviceManager.AddDevice(tpController);
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Unable to deserialize buttons collection for device: {0}", devConf.Key);
}
var butToken = devConf.Properties["buttons"];
if (butToken == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Error,
"Error: Unable to deserialize buttons collection for device: {0}", devConf.Key);
continue;
}
var buttons = butToken.ToObject<Dictionary<string, Essentials.Core.Touchpanels.KeypadButton>>();
var tpController = new Core.Touchpanels.Mpc3TouchpanelController(
string.Format("{0}-keypadButtons", devConf.Key), devConf.Name, Global.ControlSystem, buttons);
DeviceManager.AddDevice(tpController);
}
else
{
@@ -490,21 +508,17 @@ namespace PepperDash.Essentials
}
}
AddRoomAndBuildMC(room);
if (room is IEssentialsHuddleSpaceRoom)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, fusionIpId, fusionJoinMapKey));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
CreateMobileControlBridge(room);
}
else if (room is IEssentialsHuddleVtc1Room)
{
DeviceManager.AddDevice(room);
if (!(room is EssentialsCombinedHuddleVtc1Room))
{
@@ -512,28 +526,15 @@ namespace PepperDash.Essentials
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
CreateMobileControlBridge(room);
}
else if (room is EssentialsTechRoom)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice,
"Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
DeviceManager.AddDevice(new EssentialsTechRoomFusionSystemController((EssentialsTechRoom)room, fusionIpId, fusionJoinMapKey));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge");
CreateMobileControlBridge(room);
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion");
DeviceManager.AddDevice(room);
}
fusionIpId += 1;
}
else
@@ -547,6 +548,15 @@ namespace PepperDash.Essentials
}
private static void AddRoomAndBuildMC(IEssentialsRoom room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge");
CreateMobileControlBridge(room);
}
private static void CreateMobileControlBridge(object room)
{
var mobileControl = GetMobileControlDevice();

View File

@@ -71,7 +71,7 @@
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.42.30563, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.2.1.30543, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
</Reference>

View File

@@ -19,32 +19,41 @@ namespace PepperDash.Essentials.Room.Config
/// Returns a room object from this config data
/// </summary>
/// <returns></returns>
public static Device GetRoomObject(DeviceConfig roomConfig)
public static IKeyed GetRoomObject(DeviceConfig roomConfig)
{
var typeName = roomConfig.Type.ToLower();
if (typeName == "huddle")
{
return new EssentialsHuddleSpaceRoom(roomConfig);
}
if (typeName == "huddlevtc1")
switch (typeName)
{
return new EssentialsHuddleVtc1Room(roomConfig);
case "huddle" :
{
return new EssentialsHuddleSpaceRoom(roomConfig);
}
case "huddlevtc1" :
{
return new EssentialsHuddleVtc1Room(roomConfig);
}
case "ddvc01bridge" :
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
case "dualdisplay" :
{
return new EssentialsDualDisplayRoom(roomConfig);
}
case "combinedhuddlevtc1" :
{
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
}
case "techroom" :
{
return new EssentialsTechRoom(roomConfig);
}
default :
{
return Core.DeviceFactory.GetDevice(roomConfig);
}
}
if (typeName == "ddvc01bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
if (typeName == "dualdisplay")
{
return new EssentialsDualDisplayRoom(roomConfig);
}
if (typeName == "combinedhuddlevtc1")
{
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
}
return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig);
}
/// <summary>
@@ -202,6 +211,9 @@ namespace PepperDash.Essentials.Room.Config
[JsonProperty("fusion")]
public EssentialsRoomFusionConfig Fusion { get; set; }
[JsonProperty("essentialsRoomUiBehaviorConfig", NullValueHandling=NullValueHandling.Ignore)]
public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; }
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
@@ -218,6 +230,12 @@ namespace PepperDash.Essentials.Room.Config
}
}
public class EssentialsRoomUiBehaviorConfig
{
[JsonProperty("disableActivityButtonsWhileWarmingCooling")]
public bool DisableActivityButtonsWhileWarmingCooling { get; set; }
}
public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig
{
[JsonProperty("defaultAudioKey")]

View File

@@ -226,66 +226,66 @@ namespace PepperDash.Essentials
}
}
void Initialize()
public override void Initialize()
{
try
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
else if (DefaultAudioDevice is IHasVolumeDevice)
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
//if (DefaultAudioDevice is IBasicVolumeControls)
// DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
//else if (DefaultAudioDevice is IHasVolumeDevice)
// DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
//CurrentVolumeControls = DefaultVolumeControls;
// Combines call feedback from both codecs if available
InCallFeedback = new BoolFeedback(() =>
{
bool inAudioCall = false;
bool inVideoCall = false;
//// Combines call feedback from both codecs if available
//InCallFeedback = new BoolFeedback(() =>
//{
// bool inAudioCall = false;
// bool inVideoCall = false;
if (AudioCodec != null)
inAudioCall = AudioCodec.IsInCall;
// if (AudioCodec != null)
// inAudioCall = AudioCodec.IsInCall;
if (VideoCodec != null)
inVideoCall = VideoCodec.IsInCall;
// if (VideoCodec != null)
// inVideoCall = VideoCodec.IsInCall;
if (inAudioCall || inVideoCall)
return true;
else
return false;
});
// if (inAudioCall || inVideoCall)
// return true;
// else
// return false;
//});
SetupDisplays();
//SetupDisplays();
// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
//// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
//this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
Debug.Console(2, this, "Microphone Privacy Config evaluated.");
//Debug.Console(2, this, "Microphone Privacy Config evaluated.");
// Get emergency object, if any
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
//// Get emergency object, if any
//this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Debug.Console(2, this, "Emergency Config evaluated.");
//Debug.Console(2, this, "Emergency Config evaluated.");
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
//VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
//VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
if (AudioCodec != null)
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
//if (AudioCodec != null)
// AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
//IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
//VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
// link privacy to VC (for now?)
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
//// link privacy to VC (for now?)
//PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
//VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
CallTypeFeedback = new IntFeedback(() => 0);
//CallTypeFeedback = new IntFeedback(() => 0);
SetSourceListKey();
EnablePowerOnToLastSource = true;
//EnablePowerOnToLastSource = true;
}
catch (Exception e)
{
@@ -297,7 +297,9 @@ namespace PepperDash.Essentials
{
//DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
var destinationList = ConfigReader.ConfigObject.DestinationLists[PropertiesConfig.DestinationListKey];
var destinationList = ConfigReader.ConfigObject.DestinationLists[PropertiesConfig.DestinationListKey];
Displays.Clear();
foreach (var destination in destinationList)
{
@@ -314,37 +316,54 @@ namespace PepperDash.Essentials
// Link power, warming, cooling to display
var dispTwoWay = display as IHasPowerControlWithFeedback;
if (dispTwoWay != null)
{
dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
//if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
// CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
};
}
display.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
display.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
{
dispTwoWay.PowerIsOnFeedback.OutputChange -= PowerIsOnFeedback_OutputChange;
dispTwoWay.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange;
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
}
display.IsWarmingUpFeedback.OutputChange -= IsWarmingUpFeedback_OutputChange;
display.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
display.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange;
display.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
}
}
}
void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
IsCoolingDownFeedback.FireUpdate();
}
void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
}
void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
var dispTwoWay = sender as IHasPowerControlWithFeedback;
if (dispTwoWay != null && dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
//if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
// CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
}
private void SetSourceListKey()
{
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))
@@ -354,9 +373,9 @@ namespace PepperDash.Essentials
else
{
SetSourceListKey(Key);
}
SetCodecExternalSources();
}
SetUpVideoCodec();
}
protected override void CustomSetConfig(DeviceConfig config)
@@ -367,26 +386,150 @@ namespace PepperDash.Essentials
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateRoomConfig(config);
}
public override bool Deactivate()
{
// Stop listining to this event when room deactivated
VideoCodec.IsReadyChange -= VideoCodec_IsReadyChange;
// Clear occupancy
RoomOccupancy = null;
Debug.Console(0, this, "Room '{0}' Deactivated", Name);
return base.Deactivate();
}
public override bool CustomActivate()
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
{
try
{
if (DefaultAudioDevice is IBasicVolumeControls)
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
else if (DefaultAudioDevice is IHasVolumeDevice)
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
CurrentVolumeControls = DefaultVolumeControls;
// Combines call feedback from both codecs if available
InCallFeedback = new BoolFeedback(() =>
{
bool inAudioCall = false;
bool inVideoCall = false;
if (AudioCodec != null)
inAudioCall = AudioCodec.IsInCall;
if (VideoCodec != null)
inVideoCall = VideoCodec.IsInCall;
if (inAudioCall || inVideoCall)
return true;
else
return false;
});
SetupDisplays();
// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
Debug.Console(2, this, "Microphone Privacy Config evaluated.");
// Get emergency object, if any
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Debug.Console(2, this, "Emergency Config evaluated.");
if (AudioCodec != null)
{
AudioCodec.CallStatusChange -= AudioCodec_CallStatusChange;
AudioCodec.CallStatusChange += AudioCodec_CallStatusChange;
}
VideoCodec.CallStatusChange -= VideoCodec_CallStatusChange;
VideoCodec.CallStatusChange += VideoCodec_CallStatusChange;
VideoCodec.IsReadyChange -= VideoCodec_IsReadyChange;
VideoCodec.IsReadyChange += VideoCodec_IsReadyChange;
VideoCodec.SharingContentIsOnFeedback.OutputChange -= SharingContentIsOnFeedback_OutputChange;
VideoCodec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange;
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
// link privacy to VC (for now?)
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
VideoCodec.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange;
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange;
CallTypeFeedback = new IntFeedback(() => 0);
SetSourceListKey();
EnablePowerOnToLastSource = true;
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
}
catch (Exception e)
{
Debug.Console(0, this, "Error Activiating Room: {0}", e);
}
Debug.Console(0, this, "Room '{0}' Activated", Name);
return base.CustomActivate();
}
}
void AudioCodec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
InCallFeedback.FireUpdate();
}
void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PrivacyModeIsOnFeedback.FireUpdate();
}
void VideoCodec_IsReadyChange(object sender, EventArgs e)
{
SetUpVideoCodec();
}
void SetUpVideoCodec()
{
SetCodecExternalSources();
SetCodecBranding();
}
void VideoCodec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
InCallFeedback.FireUpdate();
}
void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
IsSharingFeedback.FireUpdate();
}
/// <summary>
///
@@ -779,7 +922,9 @@ namespace PepperDash.Essentials
videoCodecWithExternalSwitching.AddExternalSource(codecInputConnectorName, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop);
videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready);
}
}
}
Debug.Console(1, this, "Successfully set up codec external sources for room: {0}", Name);
}
catch (Exception e)
{

View File

@@ -19,6 +19,8 @@ namespace PepperDash.Essentials
{
public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IEssentialsHuddleVtc1Room
{
private IEssentialsRoomCombiner _roomCombiner;
private bool _codecExternalSourceChange;
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSourceChange;
@@ -234,7 +236,7 @@ namespace PepperDash.Essentials
throw new ArgumentNullException("DefaultAudioDevice cannot be null");
}
InitializeRoom();
Initialize();
}
catch (Exception e)
{
@@ -242,8 +244,65 @@ namespace PepperDash.Essentials
}
}
void InitializeRoom()
{
private void SetupEnvironmentalControlDevices()
{
if (PropertiesConfig.Environment != null)
{
if (PropertiesConfig.Environment.Enabled)
{
EnvironmentalControlDevices.Clear();
foreach (var d in PropertiesConfig.Environment.DeviceKeys)
{
var envDevice = DeviceManager.GetDeviceForKey(d) as EssentialsDevice;
EnvironmentalControlDevices.Add(envDevice);
}
}
}
}
private void SetSourceListKey()
{
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))
{
SetSourceListKey(PropertiesConfig.SourceListKey);
}
else
{
SetSourceListKey(Key);
}
SetUpVideoCodec();
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateRoomConfig(config);
}
public override bool Deactivate()
{
// Stop listining to this event when room deactivated
VideoCodec.IsReadyChange -= VideoCodec_IsReadyChange;
// Clear occupancy
RoomOccupancy = null;
Debug.Console(0, this, "Room '{0}' Deactivated", Name);
return base.Deactivate();
}
public override bool CustomActivate()
{
try
{
if (DefaultAudioDevice is IBasicVolumeControls)
@@ -278,32 +337,15 @@ namespace PepperDash.Essentials
var dispTwoWay = disp as IHasPowerControlWithFeedback;
if (dispTwoWay != null)
{
dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) =>
{
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
};
dispTwoWay.PowerIsOnFeedback.OutputChange -= PowerIsOnFeedback_OutputChange;
dispTwoWay.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange;
}
disp.IsWarmingUpFeedback.OutputChange += (o, a) =>
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
};
disp.IsCoolingDownFeedback.OutputChange += (o, a) =>
{
IsCoolingDownFeedback.FireUpdate();
};
disp.IsWarmingUpFeedback.OutputChange -= IsWarmingUpFeedback_OutputChange;
disp.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
disp.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange;
disp.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
}
@@ -317,20 +359,30 @@ namespace PepperDash.Essentials
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
Debug.Console(2, this, "Emergency Config evaluated.");
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
if (AudioCodec != null)
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
{
AudioCodec.CallStatusChange -= AudioCodec_CallStatusChange;
AudioCodec.CallStatusChange += AudioCodec_CallStatusChange;
}
VideoCodec.CallStatusChange -= VideoCodec_CallStatusChange;
VideoCodec.CallStatusChange += VideoCodec_CallStatusChange;
VideoCodec.IsReadyChange -= VideoCodec_IsReadyChange;
VideoCodec.IsReadyChange += VideoCodec_IsReadyChange;
VideoCodec.SharingContentIsOnFeedback.OutputChange -= SharingContentIsOnFeedback_OutputChange;
VideoCodec.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange;
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
// link privacy to VC (for now?)
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
VideoCodec.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange;
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange;
CallTypeFeedback = new IntFeedback(() => 0);
@@ -339,72 +391,92 @@ namespace PepperDash.Essentials
SetSourceListKey();
EnablePowerOnToLastSource = true;
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
}
catch (Exception e)
{
Debug.Console(0, this, "Error Initializing Room: {0}", e);
}
}
private void SetupEnvironmentalControlDevices()
{
if (PropertiesConfig.Environment != null)
{
if (PropertiesConfig.Environment.Enabled)
{
foreach (var d in PropertiesConfig.Environment.DeviceKeys)
{
var envDevice = DeviceManager.GetDeviceForKey(d) as EssentialsDevice;
EnvironmentalControlDevices.Add(envDevice);
}
}
}
}
private void SetSourceListKey()
{
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))
{
SetSourceListKey(PropertiesConfig.SourceListKey);
}
else
{
SetSourceListKey(Key);
Debug.Console(0, this, "Error Activiating Room: {0}", e);
}
SetCodecExternalSources();
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>(config.Properties.ToString());
if (newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateRoomConfig(config);
}
public override bool CustomActivate()
{
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
Debug.Console(0, this, "Room '{0}' Activated", Name);
return base.CustomActivate();
}
void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PrivacyModeIsOnFeedback.FireUpdate();
}
void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
IsSharingFeedback.FireUpdate();
}
void AudioCodec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
InCallFeedback.FireUpdate();
}
void VideoCodec_IsReadyChange(object sender, EventArgs e)
{
SetUpVideoCodec();
}
void SetUpVideoCodec()
{
SetCodecExternalSources();
SetCodecBranding();
}
void VideoCodec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
InCallFeedback.FireUpdate();
}
void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
IsCoolingDownFeedback.FireUpdate();
}
void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
IsWarmingUpFeedback.FireUpdate();
if (!IsWarmingUpFeedback.BoolValue)
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
}
void PowerIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
var dispTwoWay = DefaultDisplay as IHasPowerControlWithFeedback;
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
{
if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
CurrentSourceInfo = null;
OnFeedback.FireUpdate();
}
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
{
SetDefaultLevels();
}
}
/// <summary>
@@ -745,6 +817,28 @@ namespace PepperDash.Essentials
{
//Implement this
}
protected override bool AllowVacancyTimerToStart()
{
bool allowVideo = true;
bool allowAudio = true;
if (VideoCodec != null)
{
Debug.Console(2,this, Debug.ErrorLogLevel.Notice, "Room {0} {1} in a video call", Key, VideoCodec.IsInCall ? "is" : "is not");
allowVideo = !VideoCodec.IsInCall;
}
if (AudioCodec != null)
{
Debug.Console(2,this, Debug.ErrorLogLevel.Notice, "Room {0} {1} in an audio call", Key, AudioCodec.IsInCall ? "is" : "is not");
allowAudio = !AudioCodec.IsInCall;
}
Debug.Console(2, this, "Room {0} allowing vacancy timer to start: {1}", Key, allowVideo && allowAudio);
return allowVideo && allowAudio;
}
/// <summary>
/// Does what it says
@@ -810,6 +904,8 @@ namespace PepperDash.Essentials
videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready);
}
}
Debug.Console(1, this, "Successfully set up codec external sources for room: {0}", Name);
}
catch (Exception e)
{

View File

@@ -272,7 +272,7 @@ namespace PepperDash.Essentials
{
Debug.Console(2, this,
@"Attempting to run action:
DeviceKey: {0}
Key: {0}
MethodName: {1}
Params: {2}"
, a.DeviceKey, a.MethodName, a.Params);

View File

@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Core;
namespace PepperDash.Essentials
{
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay
{
bool ExcludeFromGlobalFunctions { get; }
void RunRouteAction(string routeKey);
EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; }
IBasicVolumeControls CurrentVolumeControls { get; }
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
}
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay
{
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }
void RunRouteAction(string routeKey);
IHasScheduleAwareness ScheduleSource { get; }
string DefaultCodecRouteString { get; }
}
}

View File

@@ -7,7 +7,8 @@ using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy,
IEmergency, IMicrophonePrivacy
{
bool ExcludeFromGlobalFunctions { get; }

View File

@@ -8,7 +8,8 @@ using PepperDash.Essentials.Devices.Common.AudioCodec;
namespace PepperDash.Essentials
{
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback,
IRoomOccupancy, IEmergency, IMicrophonePrivacy
{
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }

View File

@@ -11,211 +11,38 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.PageManagers;
using PepperDash.Essentials.Core.UI;
using Newtonsoft.Json;
namespace PepperDash.Essentials
{
public class EssentialsTouchpanelController : EssentialsDevice, IHasBasicTriListWithSmartObject
{
private CrestronTouchpanelPropertiesConfig _propertiesConfig;
public BasicTriListWithSmartObject Panel { get; private set; }
public class EssentialsTouchpanelController : TouchpanelBase
{
public PanelDriverBase PanelDriver { get; private set; }
CTimer BacklightTransitionedOnTimer;
public EssentialsTouchpanelController(string key, string name, Tswx52ButtonVoiceControl tsw,
string projectName, string sgdPath)
: base(key, name)
{
Panel = tsw;
if (!string.IsNullOrEmpty(sgdPath))
Panel.LoadSmartObjects(sgdPath);
else
Debug.Console(1, this, "No SGD file path defined");
tsw.SigChange += Panel_SigChange;
}
public EssentialsTouchpanelController(string key, string name, Dge100 dge, string projectName, string sgdPath)
: base(key, name)
{
Panel = dge;
if (!string.IsNullOrEmpty(sgdPath))
Panel.LoadSmartObjects(sgdPath);
else
Debug.Console(1, this, "No SGD file path defined");
dge.SigChange += Panel_SigChange;
}
/// <summary>
/// Config constructor
/// </summary>
public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id)
: base(key, name)
public EssentialsTouchpanelController(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config)
: base(key, name, panel, config)
{
_propertiesConfig = props;
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating touchpanel hardware...");
type = type.ToLower();
try
{
if (type == "crestronapp")
{
var app = new CrestronApp(id, Global.ControlSystem);
app.ParameterProjectName.Value = props.ProjectName;
Panel = app;
}
else if (type == "xpanel")
Panel = new XpanelForSmartGraphics(id, Global.ControlSystem);
else if (type == "tsw550")
Panel = new Tsw550(id, Global.ControlSystem);
else if (type == "tsw552")
Panel = new Tsw552(id, Global.ControlSystem);
else if (type == "tsw560")
Panel = new Tsw560(id, Global.ControlSystem);
else if (type == "tsw750")
Panel = new Tsw750(id, Global.ControlSystem);
else if (type == "tsw752")
Panel = new Tsw752(id, Global.ControlSystem);
else if (type == "tsw760")
Panel = new Tsw760(id, Global.ControlSystem);
else if (type == "tsw1050")
Panel = new Tsw1050(id, Global.ControlSystem);
else if (type == "tsw1052")
Panel = new Tsw1052(id, Global.ControlSystem);
else if (type == "tsw1060")
Panel = new Tsw1060(id, Global.ControlSystem);
else if (type == "tsw570")
Panel = new Tsw570(id, Global.ControlSystem);
else if (type == "tsw770")
Panel = new Tsw770(id, Global.ControlSystem);
else if (type == "ts770")
Panel = new Ts770(id, Global.ControlSystem);
else if (type == "tsw1070")
Panel = new Tsw1070(id, Global.ControlSystem);
else if (type == "ts1070")
Panel = new Ts1070(id, Global.ControlSystem);
else
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW controller with type '{0}'", type);
return;
}
}
catch (Exception e)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message);
return;
}
// Reserved sigs
if (Panel is TswFt5ButtonSystem)
{
var tsw = Panel as TswFt5ButtonSystem;
tsw.ExtenderSystemReservedSigs.Use();
tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange
+= ExtenderSystemReservedSigs_DeviceExtenderSigChange;
tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange);
}
if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success)
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason);
// Give up cleanly if SGD is not present.
var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + props.SgdFile;
if (!File.Exists(sgdName))
{
Debug.Console(0, this, "Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName);
sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + props.SgdFile;
if (!File.Exists(sgdName))
{
Debug.Console(0, this, "Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName);
return;
}
}
Panel.LoadSmartObjects(sgdName);
Panel.SigChange += Panel_SigChange;
AddPostActivationAction(() =>
{
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner;
if (roomCombiner != null)
{
// Subscribe to the even
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(roomCombiner_RoomCombinationScenarioChanged);
// Connect to the initial roomKey
if (roomCombiner.CurrentScenario != null)
{
// Use the current scenario
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
}
else
{
// Current Scenario not yet set. Use default
SetupPanelDrivers(_propertiesConfig.DefaultRoomKey);
}
}
else
{
// No room combiner, use the default key
SetupPanelDrivers(_propertiesConfig.DefaultRoomKey);
}
});
}
void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
{
var roomCombiner = sender as IEssentialsRoomCombiner;
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
}
/// <summary>
/// Determines the room key to use based on the scenario
/// </summary>
/// <param name="scenario"></param>
void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario)
{
string newRoomKey = null;
if (scenario.UiMap.ContainsKey(Key))
{
newRoomKey = scenario.UiMap[Key];
}
else if (scenario.UiMap.ContainsKey(_propertiesConfig.DefaultRoomKey))
{
newRoomKey = scenario.UiMap[_propertiesConfig.DefaultRoomKey];
}
SetupPanelDrivers(newRoomKey);
}
/// <summary>
/// Sets up drivers and links them to the room specified
/// </summary>
/// <param name="roomKey">key of room to link the drivers to</param>
void SetupPanelDrivers(string roomKey)
protected override void SetupPanelDrivers(string roomKey)
{
// Clear out any existing actions
Panel.ClearAllSigActions();
Debug.Console(0, this, "Linking TP '{0}' to Room '{1}'", Key, roomKey);
var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, _propertiesConfig);
var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, _config);
// Then the sub drivers
// spin up different room drivers depending on room type
@@ -224,15 +51,15 @@ namespace PepperDash.Essentials
{
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _propertiesConfig);
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _config);
// Header Driver
Debug.Console(0, this, "Adding header driver");
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _propertiesConfig);
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _config);
// AV Driver
Debug.Console(0, this, "Adding huddle space AV driver");
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, _propertiesConfig);
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, _config);
avDriver.DefaultRoomKey = roomKey;
mainDriver.AvDriver = avDriver;
avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom;
@@ -241,7 +68,7 @@ namespace PepperDash.Essentials
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, this, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _propertiesConfig);
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _config);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
@@ -270,13 +97,13 @@ namespace PepperDash.Essentials
Debug.Console(0, this, "Adding huddle space VTC AV driver");
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _propertiesConfig);
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, _config);
// Header Driver
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _propertiesConfig);
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, _config);
// AV Driver
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, _propertiesConfig);
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, _config);
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(Panel, avDriver,
(room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver);
@@ -289,7 +116,7 @@ namespace PepperDash.Essentials
if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0)
{
Debug.Console(0, this, "Adding environment driver");
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _propertiesConfig);
mainDriver.EnvironmentDriver = new EssentialsEnvironmentDriver(mainDriver, _config);
mainDriver.EnvironmentDriver.GetDevicesFromConfig(avDriver.CurrentRoom.PropertiesConfig.Environment);
}
@@ -338,13 +165,7 @@ namespace PepperDash.Essentials
driver.Show();
}
void HomePressed()
{
if (BacklightTransitionedOnTimer == null)
PanelDriver.BackButtonPressed();
}
void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
{
// If the sig is transitioning on, mark it in case it was home button that transitioned it
var blOnSig = (Panel as TswFt5ButtonSystem).ExtenderSystemReservedSigs.BacklightOnFeedback;
@@ -382,26 +203,6 @@ namespace PepperDash.Essentials
act(value);
}
}
void Panel_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Sig 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);
}
void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args)
{
var uo = args.Button.UserObject;
if(uo is Action<bool>)
(uo as Action<bool>)(args.Button.State == eButtonState.Pressed);
}
}
public class EssentialsTouchpanelControllerFactory : EssentialsDeviceFactory<EssentialsTouchpanelController>
@@ -414,13 +215,74 @@ namespace PepperDash.Essentials
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
var comm = CommFactory.GetControlPropertiesConfig(dc);
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<CrestronTouchpanelPropertiesConfig>(dc.Properties.ToString());
var props = JsonConvert.DeserializeObject<CrestronTouchpanelPropertiesConfig>(dc.Properties.ToString());
var panel = GetPanelForType(dc.Type, comm.IpIdInt, props.ProjectName);
if (panel == null)
{
Debug.Console(0, "Unable to create Touchpanel for type {0}. Touchpanel Controller WILL NOT function correctly", dc.Type);
}
Debug.Console(1, "Factory Attempting to create new EssentialsTouchpanelController");
var panelController = new EssentialsTouchpanelController(dc.Key, dc.Name, dc.Type, props, comm.IpIdInt);
var panelController = new EssentialsTouchpanelController(dc.Key, dc.Name, panel, props);
return panelController;
}
private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName)
{
type = type.ToLower();
try
{
if (type == "crestronapp")
{
var app = new CrestronApp(id, Global.ControlSystem);
app.ParameterProjectName.Value = projectName;
return app;
}
else if (type == "xpanel")
return new XpanelForSmartGraphics(id, Global.ControlSystem);
else if (type == "tsw550")
return new Tsw550(id, Global.ControlSystem);
else if (type == "tsw552")
return new Tsw552(id, Global.ControlSystem);
else if (type == "tsw560")
return new Tsw560(id, Global.ControlSystem);
else if (type == "tsw750")
return new Tsw750(id, Global.ControlSystem);
else if (type == "tsw752")
return new Tsw752(id, Global.ControlSystem);
else if (type == "tsw760")
return new Tsw760(id, Global.ControlSystem);
else if (type == "tsw1050")
return new Tsw1050(id, Global.ControlSystem);
else if (type == "tsw1052")
return new Tsw1052(id, Global.ControlSystem);
else if (type == "tsw1060")
return new Tsw1060(id, Global.ControlSystem);
else if (type == "tsw570")
return new Tsw570(id, Global.ControlSystem);
else if (type == "tsw770")
return new Tsw770(id, Global.ControlSystem);
else if (type == "ts770")
return new Ts770(id, Global.ControlSystem);
else if (type == "tsw1070")
return new Tsw1070(id, Global.ControlSystem);
else if (type == "ts1070")
return new Ts1070(id, Global.ControlSystem);
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW controller with type '{0}'", type);
return null;
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message);
return null;
}
}
}
}

View File

@@ -97,10 +97,10 @@ namespace PepperDash.Essentials
{
TriList.SetSigFalseAction(ButtonPressJoinBase + 1, ShadeDevice.Open);
TriList.SetSigFalseAction(ButtonPressJoinBase + 2, (ShadeDevice as IShadesOpenCloseStop).StopOrPreset);
if(ShadeDevice is RelayControlledShade)
TriList.SetString(StringJoinBase + 2, (ShadeDevice as RelayControlledShade).StopOrPresetButtonLabel);
TriList.SetSigFalseAction(ButtonPressJoinBase + 2, (ShadeDevice as IShadesOpenCloseStop).Stop);
if (ShadeDevice is IShadesOpenCloseStop)
TriList.SetString(StringJoinBase + 2, "Stop");
TriList.SetSigFalseAction(ButtonPressJoinBase + 3, ShadeDevice.Close);
}

View File

@@ -46,6 +46,33 @@ namespace PepperDash.Essentials.Core.Bridges
bridge.PrintJoinMaps();
}
}
public static void JoinmapMarkdown(string command)
{
var targets = command.Split(' ');
var bridgeKey = targets[0].Trim();
var bridge = DeviceManager.GetDeviceForKey(bridgeKey) as EiscApiAdvanced;
if (bridge == null)
{
Debug.Console(0, "Unable to find advanced bridge with key: '{0}'", bridgeKey);
return;
}
if (targets.Length > 1)
{
var deviceKey = targets[1].Trim();
if (string.IsNullOrEmpty(deviceKey)) return;
bridge.MarkdownJoinMapForDevice(deviceKey, bridgeKey);
}
else
{
bridge.MarkdownForBridge(bridgeKey);
}
}
}
@@ -82,7 +109,7 @@ namespace PepperDash.Essentials.Core.Bridges
{
public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
protected Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
public Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
public BasicTriList Eisc { get; private set; }
@@ -138,7 +165,7 @@ namespace PepperDash.Essentials.Core.Bridges
Debug.Console(1, this, "Linking Device: '{0}'", device.Key);
if (!typeof (IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType()))
if (!typeof(IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType()))
{
Debug.Console(0, this, Debug.ErrorLogLevel.Notice,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
@@ -227,6 +254,19 @@ namespace PepperDash.Essentials.Core.Bridges
joinMap.Value.PrintJoinMapInfo();
}
}
/// <summary>
/// Generates markdown for all join maps on this bridge
/// </summary>
public virtual void MarkdownForBridge(string bridgeKey)
{
Debug.Console(0, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X"));
foreach (var joinMap in JoinMaps)
{
Debug.Console(0, "Generating markdown for device '{0}':", joinMap.Key);
joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey);
}
}
/// <summary>
/// Prints the join map for a device by key
@@ -242,9 +282,26 @@ namespace PepperDash.Essentials.Core.Bridges
return;
}
Debug.Console(0, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
Debug.Console(0, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.PrintJoinMapInfo();
}
/// <summary>
/// Prints the join map for a device by key
/// </summary>
/// <param name="deviceKey"></param>
public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey)
{
var joinMap = JoinMaps[deviceKey];
if (joinMap == null)
{
Debug.Console(0, this, "Unable to find joinMap for device with key: '{0}'", deviceKey);
return;
}
Debug.Console(0, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey);
}
/// <summary>
/// Used for debugging to trigger an action based on a join number and type
@@ -352,7 +409,7 @@ namespace PepperDash.Essentials.Core.Bridges
public List<ApiDevicePropertiesConfig> Devices { get; set; }
[JsonProperty("rooms")]
public List<ApiRoomPropertiesConfig> Rooms { get; set; }
public List<ApiRoomPropertiesConfig> Rooms { get; set; }
public class ApiDevicePropertiesConfig
@@ -385,7 +442,7 @@ namespace PepperDash.Essentials.Core.Bridges
{
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" };
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
@@ -394,35 +451,51 @@ namespace PepperDash.Essentials.Core.Bridges
var controlProperties = CommFactory.GetControlPropertiesConfig(dc);
BasicTriList eisc;
switch (dc.Type.ToLower())
{
case "eiscapiadv":
case "eiscapiadvanced":
{
var eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt,
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
{
eisc = new ThreeSeriesTcpIpEthernetIntersystemCommunications(controlProperties.IpIdInt,
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
break;
}
case "eiscapiadvancedserver":
{
var eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
{
eisc = new EISCServer(controlProperties.IpIdInt, Global.ControlSystem);
break;
}
case "eiscapiadvancedclient":
{
var eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
{
eisc = new EISCClient(controlProperties.IpIdInt, controlProperties.TcpSshProperties.Address, Global.ControlSystem);
break;
}
case "vceiscapiadv":
case "vceiscapiadvanced":
{
var eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, InitialParametersClass.RoomId,
Global.ControlSystem);
return new EiscApiAdvanced(dc, eisc);
}
{
if (string.IsNullOrEmpty(controlProperties.RoomId))
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key);
eisc = null;
break;
}
eisc = new VirtualControlEISCClient(controlProperties.IpIdInt, controlProperties.RoomId,
Global.ControlSystem);
break;
}
default:
return null;
eisc = null;
break;
}
if (eisc == null)
{
return null;
}
return new EiscApiAdvanced(dc, eisc);
}
}

View File

@@ -20,6 +20,18 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete AutomaticInputRoutingEnabled = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 },
new JoinMetadata { Description = "Air Media Automatic Input Routing Enable(d)", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("HdmiInHdcpSupportOn")]
public JoinDataComplete HdmiInHdcpSupportOn = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 },
new JoinMetadata { Description = "Turns on HDCP support for HDMI in. Reports state as FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("HdmiInHdcpSupportOff")]
public JoinDataComplete HdmiInHdcpSupportOff = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 },
new JoinMetadata { Description = "Turns off HDCP support for HDMI in. Reports state as FB", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("HdmiInDisabledByHdcp")]
public JoinDataComplete HdmiInDisabledByHdcp = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 },
new JoinMetadata { Description = "Reports if ", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("VideoOut")]
public JoinDataComplete VideoOut = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Air Media Video Route Select / Feedback", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });

View File

@@ -24,6 +24,10 @@ namespace PepperDash.Essentials.Core.Bridges
JoinType = eJoinType.Digital
});
[JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DM Chassis Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
[JoinName("SystemId")]
public JoinDataComplete SystemId = new JoinDataComplete(new JoinData { JoinNumber = 10, JoinSpan = 1 },
new JoinMetadata { Description = "DM Chassis SystemId Get/Set/Trigger/", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.DigitalAnalog });

View File

@@ -8,6 +8,18 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete IsOnline = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("VideoMuteOn")]
public JoinDataComplete VideoMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Mute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("VideoMuteOff")]
public JoinDataComplete VideoMuteOff = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC UnMute Video", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("VideoMuteToggle")]
public JoinDataComplete VideoMuteToggle = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Mute Video Toggle", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital });
[JoinName("CurrentOutputResolution")]
public JoinDataComplete CurrentOutputResolution = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Current Output Resolution", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
@@ -36,6 +48,34 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete AudioVideoSource = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Audio Video Source Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
[JoinName("HdcpSupportCapability")]
public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC HDCP Support Capability", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
[JoinName("Port1HdcpState")]
public JoinDataComplete Port1HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC Port 1 (DM) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
[JoinName("Port2HdcpState")]
public JoinDataComplete Port2HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 },
new JoinMetadata { Description = "DM TX Port 2 (HDMI) HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
[JoinName("HdmiInputSync")]
public JoinDataComplete HdmiInputSync = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 },
new JoinMetadata { Description = "DM RMC HDMI Input Sync", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("HdcpInputPortCount")]
public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 1 },
new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
[JoinName("ScalerOutWallMode")]
public JoinDataComplete ScalerOutWallMode = new JoinDataComplete(new JoinData { JoinNumber = 6, JoinSpan = 1 },
new JoinMetadata { Description = "Set Wall Mode for Scaler video Wall mode", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
[JoinName("ScalerOutWallModeRaw")]
public JoinDataComplete ScalerOutWallModeRaw = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 },
new JoinMetadata { Description = "Set Wall Mode for Scaler video Wall mode", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
@@ -50,7 +90,8 @@ namespace PepperDash.Essentials.Core.Bridges
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmRmcControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
protected DmRmcControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}

View File

@@ -64,6 +64,16 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete VgaContrast = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 },
new JoinMetadata { Description = "DM TX Online", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
[JoinName("Port3HdcpState")]
public JoinDataComplete Port3HdcpState = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 },
new JoinMetadata { Description = "DM TX Port 3 HDCP State Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
[JoinName("HdcpInputPortCount")]
public JoinDataComplete HdcpInputPortCount = new JoinDataComplete(new JoinData { JoinNumber = 9, JoinSpan = 1 },
new JoinMetadata { Description = "Number of Input Ports that support HDCP", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
@@ -78,7 +88,8 @@ namespace PepperDash.Essentials.Core.Bridges
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected DmTxControllerJoinMap(uint joinStart, Type type) : base(joinStart, type)
protected DmTxControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}

View File

@@ -17,6 +17,10 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete MixerPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 3, JoinSpan = 1 },
new JoinMetadata { Description = "Mixer Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog });
[JoinName("MixerEqPresetRecall")]
public JoinDataComplete MixerEqPresetRecall = new JoinDataComplete(new JoinData { JoinNumber = 4, JoinSpan = 1 },
new JoinMetadata { Description = "Mixer Eq Preset Recall Set", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog });
[JoinName("MasterVolumeMuteOn")]
public JoinDataComplete MasterVolumeMuteOn = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Master Volume Mute On Set / Get", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });

View File

@@ -0,0 +1,827 @@
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Bridges.JoinMaps
{
public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced
{
[JoinName("PLAY")]
public JoinDataComplete Play = new JoinDataComplete(
new JoinData
{
JoinNumber = 1,
JoinSpan = 1
},
new JoinMetadata
{
Description = "PLAY",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("STOP")]
public JoinDataComplete Stop = new JoinDataComplete(
new JoinData
{
JoinNumber = 2,
JoinSpan = 1
},
new JoinMetadata
{
Description = "STOP",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PAUSE")]
public JoinDataComplete Pause = new JoinDataComplete(
new JoinData
{
JoinNumber = 3,
JoinSpan = 1
},
new JoinMetadata
{
Description = "PAUSE",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("FSCAN")]
public JoinDataComplete ForwardScan = new JoinDataComplete(
new JoinData
{
JoinNumber = 4,
JoinSpan = 1
},
new JoinMetadata
{
Description = "FSCAN",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("RSCAN")]
public JoinDataComplete ReverseScan = new JoinDataComplete(
new JoinData
{
JoinNumber = 5,
JoinSpan = 1
},
new JoinMetadata
{
Description = "RSCAN",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("F_SKIP")]
public JoinDataComplete ForwardSkip = new JoinDataComplete(
new JoinData
{
JoinNumber = 6,
JoinSpan = 1
},
new JoinMetadata
{
Description = "F_SKIP",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("R_SKIP")]
public JoinDataComplete ReverseSkip = new JoinDataComplete(
new JoinData
{
JoinNumber = 7,
JoinSpan = 1
},
new JoinMetadata
{
Description = "R_SKIP",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("RECORD")]
public JoinDataComplete Record = new JoinDataComplete(
new JoinData
{
JoinNumber = 8,
JoinSpan = 1
},
new JoinMetadata
{
Description = "RECORD",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("POWER")]
public JoinDataComplete Power = new JoinDataComplete(
new JoinData
{
JoinNumber = 9,
JoinSpan = 1
},
new JoinMetadata
{
Description = "POWER",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("0")]
public JoinDataComplete Kp0 = new JoinDataComplete(
new JoinData
{
JoinNumber = 10,
JoinSpan = 1
},
new JoinMetadata
{
Description = "0",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("1")]
public JoinDataComplete Kp1 = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "1",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("2")]
public JoinDataComplete Kp2 = new JoinDataComplete(
new JoinData
{
JoinNumber = 12,
JoinSpan = 1
},
new JoinMetadata
{
Description = "2",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("3")]
public JoinDataComplete Kp3 = new JoinDataComplete(
new JoinData
{
JoinNumber = 13,
JoinSpan = 1
},
new JoinMetadata
{
Description = "3",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("4")]
public JoinDataComplete Kp4 = new JoinDataComplete(
new JoinData
{
JoinNumber = 14,
JoinSpan = 1
},
new JoinMetadata
{
Description = "4",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("5")]
public JoinDataComplete Kp5 = new JoinDataComplete(
new JoinData
{
JoinNumber = 15,
JoinSpan = 1
},
new JoinMetadata
{
Description = "5",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("6")]
public JoinDataComplete Kp6 = new JoinDataComplete(
new JoinData
{
JoinNumber = 16,
JoinSpan = 1
},
new JoinMetadata
{
Description = "6",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("7")]
public JoinDataComplete Kp7 = new JoinDataComplete(
new JoinData
{
JoinNumber = 17,
JoinSpan = 1
},
new JoinMetadata
{
Description = "7",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("8")]
public JoinDataComplete Kp8 = new JoinDataComplete(
new JoinData
{
JoinNumber = 18,
JoinSpan = 1
},
new JoinMetadata
{
Description = "8",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("9")]
public JoinDataComplete Kp9 = new JoinDataComplete(
new JoinData
{
JoinNumber = 19,
JoinSpan = 1
},
new JoinMetadata
{
Description = "9",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
// [JoinName("+10")]
// public JoinDataComplete Kp9 = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 20,
// JoinSpan = 1
// },
// new JoinMetadata
// {
// Description = "+10",
// JoinCapabilities = eJoinCapabilities.FromSIMPL,
// JoinType = eJoinType.Digital
// });
[JoinName("ENTER")]
public JoinDataComplete Enter = new JoinDataComplete(
new JoinData
{
JoinNumber = 21,
JoinSpan = 1
},
new JoinMetadata
{
Description = "ENTER",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CH+")]
public JoinDataComplete ChannelUp = new JoinDataComplete(
new JoinData
{
JoinNumber = 22,
JoinSpan = 1
},
new JoinMetadata
{
Description = "CH+",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CH-")]
public JoinDataComplete ChannelDown = new JoinDataComplete(
new JoinData
{
JoinNumber = 23,
JoinSpan = 1
},
new JoinMetadata
{
Description = "CH-",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("*")]
public JoinDataComplete KpStar = new JoinDataComplete(
new JoinData
{
JoinNumber = 24,
JoinSpan = 1
},
new JoinMetadata
{
Description = "*",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("#")]
public JoinDataComplete KpPound = new JoinDataComplete(
new JoinData
{
JoinNumber = 25,
JoinSpan = 1
},
new JoinMetadata
{
Description = "#",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
// [JoinName(".")]
// public JoinDataComplete KpPound = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 26,
// JoinSpan = 1
// },
// new JoinMetadata
// {
// Description = ".",
// JoinCapabilities = eJoinCapabilities.FromSIMPL,
// JoinType = eJoinType.Digital
// });
[JoinName("POWER_ON")]
public JoinDataComplete PowerOn = new JoinDataComplete(
new JoinData
{
JoinNumber = 27,
JoinSpan = 1
},
new JoinMetadata
{
Description = "POWER_ON",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("POWER_OFF")]
public JoinDataComplete PowerOff = new JoinDataComplete(
new JoinData
{
JoinNumber = 28,
JoinSpan = 1
},
new JoinMetadata
{
Description = "POWER_OFF",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PLAY_PAUSE")]
public JoinDataComplete PlayPause = new JoinDataComplete(
new JoinData
{
JoinNumber = 29,
JoinSpan = 1
},
new JoinMetadata
{
Description = "PLAY_PAUSE",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LAST")]
public JoinDataComplete Last = new JoinDataComplete(
new JoinData
{
JoinNumber = 30,
JoinSpan = 1
},
new JoinMetadata
{
Description = "LAST",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("HOME")]
public JoinDataComplete Home = new JoinDataComplete(
new JoinData
{
JoinNumber = 40,
JoinSpan = 1
},
new JoinMetadata
{
Description = "HOME",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("BACK")]
public JoinDataComplete Back = new JoinDataComplete(
new JoinData
{
JoinNumber = 41,
JoinSpan = 1
},
new JoinMetadata
{
Description = "BACK",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("GUIDE")]
public JoinDataComplete Guide = new JoinDataComplete(
new JoinData
{
JoinNumber = 42,
JoinSpan = 1
},
new JoinMetadata
{
Description = "GUIDE",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("INFO")]
public JoinDataComplete Info = new JoinDataComplete(
new JoinData
{
JoinNumber = 43,
JoinSpan = 1
},
new JoinMetadata
{
Description = "INFO",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("MENU")]
public JoinDataComplete Menu = new JoinDataComplete(
new JoinData
{
JoinNumber = 44,
JoinSpan = 1
},
new JoinMetadata
{
Description = "MENU",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("UP_ARROW")]
public JoinDataComplete DpadUp = new JoinDataComplete(
new JoinData
{
JoinNumber = 45,
JoinSpan = 1
},
new JoinMetadata
{
Description = "UP_ARROW",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DN_ARROW")]
public JoinDataComplete DpadDown = new JoinDataComplete(
new JoinData
{
JoinNumber = 46,
JoinSpan = 1
},
new JoinMetadata
{
Description = "DN_ARROW",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("LEFT_ARROW")]
public JoinDataComplete DpadLeft = new JoinDataComplete(
new JoinData
{
JoinNumber = 47,
JoinSpan = 1
},
new JoinMetadata
{
Description = "LEFT_ARROW",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("RIGHT_ARROW")]
public JoinDataComplete DpadRight = new JoinDataComplete(
new JoinData
{
JoinNumber = 48,
JoinSpan = 1
},
new JoinMetadata
{
Description = "RIGHT_ARROW",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("SELECT")]
public JoinDataComplete DpadSelect = new JoinDataComplete(
new JoinData
{
JoinNumber = 49,
JoinSpan = 1
},
new JoinMetadata
{
Description = "SELECT",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("OPTIONS")]
public JoinDataComplete Options = new JoinDataComplete(
new JoinData
{
JoinNumber = 50,
JoinSpan = 1
},
new JoinMetadata
{
Description = "OPTIONS",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("RETURN")]
public JoinDataComplete Return = new JoinDataComplete(
new JoinData
{
JoinNumber = 51,
JoinSpan = 1
},
new JoinMetadata
{
Description = "RETURN",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DVR")]
public JoinDataComplete Dvr = new JoinDataComplete(
new JoinData
{
JoinNumber = 52,
JoinSpan = 1
},
new JoinMetadata
{
Description = "DVR",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("ON_DEMAND")]
public JoinDataComplete OnDemand = new JoinDataComplete(
new JoinData
{
JoinNumber = 53,
JoinSpan = 1
},
new JoinMetadata
{
Description = "ON_DEMAND",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PAGE_UP")]
public JoinDataComplete PageUp = new JoinDataComplete(
new JoinData
{
JoinNumber = 54,
JoinSpan = 1
},
new JoinMetadata
{
Description = "PAGE_UP",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PAGE_DOWN")]
public JoinDataComplete PageDown = new JoinDataComplete(
new JoinData
{
JoinNumber = 55,
JoinSpan = 1
},
new JoinMetadata
{
Description = "PAGE_DOWN",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("F_SRCH")]
public JoinDataComplete ForwardSearch = new JoinDataComplete(
new JoinData
{
JoinNumber = 56,
JoinSpan = 1
},
new JoinMetadata
{
Description = "F_SRCH",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("R_SRCH")]
public JoinDataComplete ReverseSearch = new JoinDataComplete(
new JoinData
{
JoinNumber = 57,
JoinSpan = 1
},
new JoinMetadata
{
Description = "R_SRCH",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("TRACK+")]
public JoinDataComplete TrackPlus = new JoinDataComplete(
new JoinData
{
JoinNumber = 58,
JoinSpan = 1
},
new JoinMetadata
{
Description = "TRACK+",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("TRACK-")]
public JoinDataComplete TrackMinus = new JoinDataComplete(
new JoinData
{
JoinNumber = 59,
JoinSpan = 1
},
new JoinMetadata
{
Description = "TRACK-",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("A")]
public JoinDataComplete KpA = new JoinDataComplete(
new JoinData
{
JoinNumber = 61,
JoinSpan = 1
},
new JoinMetadata
{
Description = "A",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("B")]
public JoinDataComplete KpB = new JoinDataComplete(
new JoinData
{
JoinNumber = 62,
JoinSpan = 1
},
new JoinMetadata
{
Description = "B",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("C")]
public JoinDataComplete KpC = new JoinDataComplete(
new JoinData
{
JoinNumber = 63,
JoinSpan = 1
},
new JoinMetadata
{
Description = "C",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("D")]
public JoinDataComplete KpD = new JoinDataComplete(
new JoinData
{
JoinNumber = 64,
JoinSpan = 1
},
new JoinMetadata
{
Description = "D",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("RED")]
public JoinDataComplete KpRed = new JoinDataComplete(
new JoinData
{
JoinNumber = 65,
JoinSpan = 1
},
new JoinMetadata
{
Description = "RED",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("GREEN")]
public JoinDataComplete KpGreen = new JoinDataComplete(
new JoinData
{
JoinNumber = 66,
JoinSpan = 1
},
new JoinMetadata
{
Description = "GREEN",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("YELLOW")]
public JoinDataComplete KpYellow = new JoinDataComplete(
new JoinData
{
JoinNumber = 67,
JoinSpan = 1
},
new JoinMetadata
{
Description = "YELLOW",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("BLUE")]
public JoinDataComplete KpBlue = new JoinDataComplete(
new JoinData
{
JoinNumber = 68,
JoinSpan = 1
},
new JoinMetadata
{
Description = "BLUE",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
public GenericIrControllerJoinMap(uint joinStart)
: base(joinStart, typeof(GenericIrControllerJoinMap))
{
}
}
}

View File

@@ -0,0 +1,190 @@
using System;
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Bridges
{
public class HdPsXxxControllerJoinMap : JoinMapBaseAdvanced
{
#region Digital
[JoinName("EnableAutoRoute")]
public JoinDataComplete EnableAutoRoute = new JoinDataComplete(
new JoinData
{
JoinNumber = 1,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Enable Automatic Routing on Xx1 Switchers",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("InputSync")]
public JoinDataComplete InputSync = new JoinDataComplete(
new JoinData
{
JoinNumber = 2,
JoinSpan = 8
},
new JoinMetadata
{
Description = "Device Input Sync",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("EnableInputHdcp")]
public JoinDataComplete EnableInputHdcp = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 8
},
new JoinMetadata
{
Description = "Device Enable Input Hdcp",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DisableInputHdcp")]
public JoinDataComplete DisableInputHdcp = new JoinDataComplete(
new JoinData
{
JoinNumber = 21,
JoinSpan = 8
},
new JoinMetadata
{
Description = "Device Disnable Input Hdcp",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(
new JoinData
{
JoinNumber = 30,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Device Onlne",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
#endregion
#region Analog
[JoinName("OutputRoute")]
public JoinDataComplete OutputRoute = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 2
},
new JoinMetadata
{
Description = "Device Output Route Set/Get",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
});
#endregion
#region Serial
[JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(
new JoinData
{
JoinNumber = 1,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Device Name",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("InputName")]
public JoinDataComplete InputName = new JoinDataComplete(
new JoinData
{
JoinNumber = 2,
JoinSpan = 8
},
new JoinMetadata
{
Description = "Device Input Name",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("OutputName")]
public JoinDataComplete OutputName = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 2
},
new JoinMetadata
{
Description = "Device Output Name",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("OutputRoutedName")]
public JoinDataComplete OutputRoutedName = new JoinDataComplete(
new JoinData
{
JoinNumber = 16,
JoinSpan = 2
},
new JoinMetadata
{
Description = "Device Output Route Name",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
#endregion
/// <summary>
/// Constructor to use when instantiating this join map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public HdPsXxxControllerJoinMap(uint joinStart)
: this(joinStart, typeof(HdPsXxxControllerJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected HdPsXxxControllerJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
namespace PepperDash.Essentials.Core.Bridges
{
public class IAnalogInputJoinMap : JoinMapBaseAdvanced
{
[JoinName("InputValue")]
public JoinDataComplete InputValue = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Input Value", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
[JoinName("MinimumChange")]
public JoinDataComplete MinimumChange = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 },
new JoinMetadata { Description = "Minimum voltage change required to reflect a change", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Analog });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public IAnalogInputJoinMap(uint joinStart)
: this(joinStart, typeof(IAnalogInputJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected IAnalogInputJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -1,13 +1,13 @@
using System;
namespace PepperDash.Essentials.Core.Bridges
{
public class IDigitalInputJoinMap : JoinMapBaseAdvanced
{
namespace PepperDash.Essentials.Core.Bridges
{
public class IDigitalInputJoinMap : JoinMapBaseAdvanced
{
[JoinName("InputState")]
public JoinDataComplete InputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Room Email Url", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
new JoinMetadata { Description = "Input State", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
@@ -26,6 +26,6 @@ namespace PepperDash.Essentials.Core.Bridges
protected IDigitalInputJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
namespace PepperDash.Essentials.Core.Bridges
{
public class IDigitalOutputJoinMap : JoinMapBaseAdvanced
{
[JoinName("OutputState")]
public JoinDataComplete OutputState = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Get / Set state of Digital Input", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public IDigitalOutputJoinMap(uint joinStart)
: this(joinStart, typeof(IDigitalOutputJoinMap))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
protected IDigitalOutputJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
namespace PepperDash.Essentials.Core.Bridges
{
public class PduJoinMapBase : JoinMapBaseAdvanced
{
[JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
[JoinName("Online")]
public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Online", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletCount")]
public JoinDataComplete OutletCount = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Number of COntrolled Outlets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
[JoinName("OutletName")]
public JoinDataComplete OutletName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
[JoinName("OutletEnabled")]
public JoinDataComplete OutletEnabled = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Enabled", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletPowerCycle")]
public JoinDataComplete OutletPowerCycle = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Power Cycle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletPowerOn")]
public JoinDataComplete OutletPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletPowerOff")]
public JoinDataComplete OutletPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public PduJoinMapBase(uint joinStart)
:base(joinStart, typeof(PduJoinMapBase))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
public PduJoinMapBase(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -47,7 +47,7 @@ namespace PepperDash.Essentials.Core.Bridges
[JoinName("ProgramOffsetJoin")]
public JoinDataComplete ProgramOffsetJoin = new JoinDataComplete(new JoinData { JoinNumber = 5, JoinSpan = 5 },
new JoinMetadata { Description = "All Program Data is offset between slots by 5 - First Joins Start at 11", JoinCapabilities = eJoinCapabilities.None, JoinType = eJoinType.None });
[JoinName("ProgramStart")]
public JoinDataComplete ProgramStart = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
new JoinMetadata { Description = "Processor Program Start / Fb", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
@@ -132,6 +132,23 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete DhcpStatus = new JoinDataComplete(new JoinData { JoinNumber = 86, JoinSpan = 1 },
new JoinMetadata { Description = "Processor Ethernet Dhcp Status", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
[JoinName("ProcessorRebot")]
public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Reboot processor", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital });
[JoinName("IsAppliance")]
public JoinDataComplete IsAppliance = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Is appliance Fb", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("IsServer")]
public JoinDataComplete IsServer = new JoinDataComplete(new JoinData { JoinNumber = 2, JoinSpan = 1 },
new JoinMetadata { Description = "Is server Fb", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("ProgramReset")]
public JoinDataComplete ProgramReset = new JoinDataComplete(new JoinData { JoinNumber = 15, JoinSpan = 1 },
new JoinMetadata { Description = "Resets the program", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{
@@ -398,6 +398,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("DirectoryEntryIsContact")]
public JoinDataComplete DirectoryEntryIsContact = new JoinDataComplete(
new JoinData
@@ -524,6 +525,21 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("DirectoryClearSelected")]
public JoinDataComplete DirectoryClearSelected = new JoinDataComplete(
new JoinData
{
JoinNumber = 110,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Clear Selected Entry and String from Search",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("CameraTiltUp")]
public JoinDataComplete CameraTiltUp = new JoinDataComplete(
new JoinData
@@ -776,44 +792,16 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Digital
});
[JoinName("DialMeeting1")]
public JoinDataComplete DialMeeting1 = new JoinDataComplete(
[JoinName("DialMeetingStart")]
public JoinDataComplete DialMeetingStart = new JoinDataComplete(
new JoinData
{
JoinNumber = 161,
JoinSpan = 1
JoinSpan = 10
},
new JoinMetadata
{
Description = "Join first meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DialMeeting2")]
public JoinDataComplete DialMeeting2 = new JoinDataComplete(
new JoinData
{
JoinNumber = 162,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Join second meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DialMeeting3")]
public JoinDataComplete DialMeeting3 = new JoinDataComplete(
new JoinData
{
JoinNumber = 163,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Join third meeting",
Description = "Join meeting",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
@@ -1256,11 +1244,12 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
},
new JoinMetadata
{
Description = "Directory Select Row",
Description = "Directory Select Row and Feedback",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("SelectedContactMethodCount")]
public JoinDataComplete SelectedContactMethodCount = new JoinDataComplete(
new JoinData
@@ -1289,6 +1278,22 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Analog
});
[JoinName("DirectorySelectRowFeedback")]
public JoinDataComplete DirectorySelectRowFeedback = new JoinDataComplete(
new JoinData
{
JoinNumber = 104,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Directory Select Row and Feedback",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("CameraPresetSelect")]
public JoinDataComplete CameraPresetSelect = new JoinDataComplete(
new JoinData
@@ -1576,6 +1581,36 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Serial
});
[JoinName("AvailableLayoutsFb")]
public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "xSig of all available layouts",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("SelectLayout")]
public JoinDataComplete SelectLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Select Layout by string",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CurrentParticipants")]
public JoinDataComplete CurrentParticipants = new JoinDataComplete(
new JoinData
@@ -3014,6 +3049,35 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Serial
});
[JoinName("AvailableLayoutsFb")]
public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "xSig of all available layouts",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("SelectLayout")]
public JoinDataComplete SelectLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Select Layout by string",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CurrentParticipants")]
public JoinDataComplete CurrentParticipants = new JoinDataComplete(
new JoinData
@@ -3111,4 +3175,4 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
{
}
}
}
}

View File

@@ -81,6 +81,15 @@ namespace PepperDash.Essentials.Core
}
case eControlMethod.Telnet:
break;
case eControlMethod.SecureTcpIp:
{
var secureTcp = new GenericSecureTcpIpClient(deviceConfig.Key + "-secureTcp", c.Address, c.Port, c.BufferSize);
secureTcp.AutoReconnect = c.AutoReconnect;
if (secureTcp.AutoReconnect)
secureTcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
comm = secureTcp;
break;
}
default:
break;
}
@@ -115,41 +124,54 @@ namespace PepperDash.Essentials.Core
/// <returns></returns>
public static ICec GetCecPort(ControlPropertiesConfig config)
{
var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey);
try
{
var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey);
if (dev != null)
{
if (!String.IsNullOrEmpty(config.ControlPortName))
{
Debug.Console(0, "GetCecPort: device '{0}' {1}", config.ControlPortDevKey, dev == null
? "is not valid, failed to get cec port"
: "found in device manager, attempting to get cec port");
var inputPort = (dev as IRoutingInputsOutputs).InputPorts[config.ControlPortName];
if (dev == null)
return null;
if (inputPort != null)
{
if (inputPort.Port is ICec)
return inputPort.Port as ICec;
}
if (String.IsNullOrEmpty(config.ControlPortName))
{
Debug.Console(0, "GetCecPort: '{0}' - Configuration missing 'ControlPortName'", config.ControlPortDevKey);
return null;
}
var outputPort = (dev as IRoutingInputsOutputs).OutputPorts[config.ControlPortName];
if (outputPort != null)
{
if (outputPort.Port is ICec)
return outputPort.Port as ICec;
}
var inputsOutputs = dev as IRoutingInputsOutputs;
if (inputsOutputs == null)
{
Debug.Console(0, "GetCecPort: Device '{0}' does not support IRoutingInputsOutputs, failed to get CEC port called '{1}'",
config.ControlPortDevKey, config.ControlPortName);
else
Debug.Console(0, "GetCecPort: Device '{0}' does not have a CEC port called: '{1}'",
config.ControlPortDevKey, config.ControlPortName);
}
else
{
Debug.Console(0, "GetCecPort: '{0}' - Configuration missing 'ControlPortName'", config.ControlPortDevKey);
}
}
Debug.Console(0, "GetCecPort: Device '{0}' is not a valid device.", config.ControlPortDevKey);
return null;
}
return null;
var inputPort = inputsOutputs.InputPorts[config.ControlPortName];
if (inputPort != null && inputPort.Port is ICec)
return inputPort.Port as ICec;
var outputPort = inputsOutputs.OutputPorts[config.ControlPortName];
if (outputPort != null && outputPort.Port is ICec)
return outputPort.Port as ICec;
}
catch (Exception ex)
{
Debug.Console(1, "GetCecPort Exception Message: {0}", ex.Message);
Debug.Console(2, "GetCecPort Exception StackTrace: {0}", ex.StackTrace);
if (ex.InnerException != null)
Debug.Console(0, "GetCecPort Exception InnerException: {0}", ex.InnerException);
}
Debug.Console(0, "GetCecPort: Device '{0}' does not have a CEC port called '{1}'",
config.ControlPortDevKey, config.ControlPortName);
return null;
}
/// <summary>
@@ -183,6 +205,8 @@ namespace PepperDash.Essentials.Core
[JsonConverter(typeof(ComSpecJsonConverter))]
public ComPort.ComPortSpec ComParams { get; set; }
public string RoomId { get; set; }
public string CresnetId { get; set; }
/// <summary>

View File

@@ -224,12 +224,18 @@ namespace PepperDash.Essentials.Core
/// </summary>
public class IrOutPortConfig
{
[JsonProperty("port")]
public IROutputPort Port { get; set; }
[JsonProperty("fileName")]
public string FileName { get; set; }
[JsonProperty("useBridgeJoinMap")]
public bool UseBridgeJoinMap { get; set; }
public IrOutPortConfig()
{
FileName = "";
FileName = "";
}
}
}

View File

@@ -1,35 +1,35 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Config
{
public class DeviceConfig
{
[JsonProperty("key")]
public string Key { get; set; }
[JsonProperty("uid")]
public int Uid { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("group")]
public string Group { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("properties")]
[JsonConverter(typeof(DevicePropertiesConverter))]
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Config
{
public class DeviceConfig
{
[JsonProperty("key")]
public string Key { get; set; }
[JsonProperty("uid")]
public int Uid { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("group")]
public string Group { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("properties")]
[JsonConverter(typeof(DevicePropertiesConverter))]
public JToken Properties { get; set; }
public DeviceConfig(DeviceConfig dc)
@@ -39,39 +39,42 @@ namespace PepperDash.Essentials.Core.Config
Name = dc.Name;
Group = dc.Group;
Type = dc.Type;
Properties = JToken.FromObject(dc.Properties);
Properties = JToken.Parse(dc.Properties.ToString());
//Properties = JToken.FromObject(dc.Properties);
}
public DeviceConfig() {}
}
/// <summary>
///
/// </summary>
public class DevicePropertiesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(JToken);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return JToken.ReadFrom(reader);
}
public override bool CanWrite
{
get
{
return false;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("SOD OFF HOSER");
}
}
}
/// <summary>
///
/// </summary>
public class DevicePropertiesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(JToken);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return JToken.ReadFrom(reader);
}
public override bool CanWrite
{
get
{
return false;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("SOD OFF HOSER");
}
}
}

View File

@@ -0,0 +1,85 @@
using System.Collections.Generic;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.CrestronIO
{
/// <summary>
/// Wrapper class for CEN-IO-COM-Xxx expander module
/// </summary>
[Description("Wrapper class for the CEN-IO-COM-102 & CEN-IO-COM-202 expander module")]
public class CenIoComController : CrestronGenericBaseDevice, IComPorts
{
private readonly CenIoCom _cenIoCom;
public CenIoComController(string key, string name, CenIoCom cenIo)
:base(key, name, cenIo)
{
_cenIoCom = cenIo;
}
#region Implementation of IComPorts
public CrestronCollection<ComPort> ComPorts
{
get { return _cenIoCom.ComPorts; }
}
public int NumberOfComPorts
{
get { return _cenIoCom.NumberOfComPorts; }
}
#endregion
}
public class CenIoCom102ControllerFactory : EssentialsDeviceFactory<CenIoComController>
{
private const string CenIoCom102Type = "ceniocom102";
private const string CenIoCom202Type = "ceniocom202";
public CenIoCom102ControllerFactory()
{
TypeNames = new List<string> { CenIoCom102Type, CenIoCom202Type };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new CEN-IO-COM-Xxx Device");
var control = CommFactory.GetControlPropertiesConfig(dc);
if (control == null)
{
Debug.Console(1, "Factory failed to create a new CEN-IO-COM-Xxx Device, control properties not found");
return null;
}
var ipid = control.IpIdInt;
if (ipid < 2)
{
Debug.Console(1, "Factory failed to create a new CEN-IO-COM-Xxx Device, invalid IP-ID found");
return null;
}
switch (dc.Type)
{
case CenIoCom102Type:
{
return new CenIoComController(dc.Key, dc.Name, new CenIoCom102(ipid, Global.ControlSystem));
}
case CenIoCom202Type:
{
return new CenIoComController(dc.Key, dc.Name, new CenIoCom202(ipid, Global.ControlSystem));
}
default:
{
Debug.Console(1, "Factory failed to create a new CEN-IO-COM-Xxx Device, invalid type '{0}'", dc.Type);
return null;
}
}
}
}
}

View File

@@ -34,7 +34,7 @@ namespace PepperDash.Essentials.Core
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new C2N-RTHS Device");
Debug.Console(1, "Factory Attempting to create new DIN-CEN-CN2 Device");
var control = CommFactory.GetControlPropertiesConfig(dc);
var ipid = control.IpIdInt;

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.CrestronIO
{
public class DinIo8Controller:CrestronGenericBaseDevice, IIOPorts
{
private DinIo8 _device;
public DinIo8Controller(string key, Func<DeviceConfig, DinIo8> preActivationFunc, DeviceConfig config):base(key, config.Name)
{
AddPreActivationAction(() =>
{
_device = preActivationFunc(config);
RegisterCrestronGenericBase(_device);
});
}
#region Implementation of IIOPorts
public CrestronCollection<Versiport> VersiPorts
{
get { return _device.VersiPorts; }
}
public int NumberOfVersiPorts
{
get { return _device.NumberOfVersiPorts; }
}
#endregion
}
public class DinIo8ControllerFactory : EssentialsDeviceFactory<DinIo8Controller>
{
public DinIo8ControllerFactory()
{
TypeNames = new List<string>() { "DinIo8" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new DinIo8 Device");
return new DinIo8Controller(dc.Key, GetDinIo8Device, dc);
}
static DinIo8 GetDinIo8Device(DeviceConfig dc)
{
var control = CommFactory.GetControlPropertiesConfig(dc);
var cresnetId = control.CresnetIdInt;
var branchId = control.ControlPortNumber;
var parentKey = string.IsNullOrEmpty(control.ControlPortDevKey) ? "processor" : control.ControlPortDevKey;
if (parentKey.Equals("processor", StringComparison.CurrentCultureIgnoreCase))
{
Debug.Console(0, "Device {0} is a valid cresnet master - creating new DinIo8", parentKey);
return new DinIo8(cresnetId, Global.ControlSystem);
}
var cresnetBridge = DeviceManager.GetDeviceForKey(parentKey) as IHasCresnetBranches;
if (cresnetBridge != null)
{
Debug.Console(0, "Device {0} is a valid cresnet master - creating new DinIo8", parentKey);
return new DinIo8(cresnetId, cresnetBridge.CresnetBranches[branchId]);
}
Debug.Console(0, "Device {0} is not a valid cresnet master", parentKey);
return null;
}
}
}

View File

@@ -15,5 +15,7 @@ namespace PepperDash.Essentials.Core.CrestronIO
public uint PortNumber { get; set; }
[JsonProperty("disablePullUpResistor")]
public bool DisablePullUpResistor { get; set; }
[JsonProperty("minimumChange")]
public int MinimumChange { get; set; }
}
}

View File

@@ -16,7 +16,7 @@ namespace PepperDash.Essentials.Core
/// Wrapper class for CEN-IO-DIGIN-104 digital input module
/// </summary>
[Description("Wrapper class for the CEN-IO-DIGIN-104 diginal input module")]
public class CenIoDigIn104Controller : EssentialsDevice, IDigitalInputPorts
public class CenIoDigIn104Controller : CrestronGenericBaseDevice, IDigitalInputPorts
{
public CenIoDi104 Di104 { get; private set; }
@@ -52,10 +52,17 @@ namespace PepperDash.Essentials.Core
{
Debug.Console(1, "Factory Attempting to create new CEN-DIGIN-104 Device");
var control = CommFactory.GetControlPropertiesConfig(dc);
var ipid = control.IpIdInt;
return new CenIoDigIn104Controller(dc.Key, dc.Name, new Crestron.SimplSharpPro.GeneralIO.CenIoDi104(ipid, Global.ControlSystem));
var control = CommFactory.GetControlPropertiesConfig(dc);
if (control == null)
{
Debug.Console(1, "Factory failed to create a new CEN-DIGIN-104 Device, control properties not found");
return null;
}
var ipid = control.IpIdInt;
if (ipid != 0) return new CenIoDigIn104Controller(dc.Key, dc.Name, new CenIoDi104(ipid, Global.ControlSystem));
Debug.Console(1, "Factory failed to create a new CEN-IO-IR-104 Device using IP-ID-{0}", ipid);
return null;
}
}

View File

@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Bridges;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core.CrestronIO
{
/// <summary>
/// Represents a generic digital input deviced tied to a versiport
/// </summary>
public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput
{
public Versiport InputPort { get; private set; }
public IntFeedback InputValueFeedback { get; private set; }
public IntFeedback InputMinimumChangeFeedback { get; private set; }
Func<int> InputValueFeedbackFunc
{
get
{
return () => InputPort.AnalogIn;
}
}
Func<int> InputMinimumChangeFeedbackFunc
{
get { return () => InputPort.AnalogMinChange; }
}
public GenericVersiportAnalogInputDevice(string key, string name, Func<IOPortConfig, Versiport> postActivationFunc, IOPortConfig config) :
base(key, name)
{
InputValueFeedback = new IntFeedback(InputValueFeedbackFunc);
InputMinimumChangeFeedback = new IntFeedback(InputMinimumChangeFeedbackFunc);
AddPostActivationAction(() =>
{
InputPort = postActivationFunc(config);
InputPort.Register();
InputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput);
InputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655);
if (config.DisablePullUpResistor)
InputPort.DisablePullUpResistor = true;
InputPort.VersiportChange += InputPort_VersiportChange;
Debug.Console(1, this, "Created GenericVersiportAnalogInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor);
});
}
/// <summary>
/// Set minimum voltage change for device to update voltage changed method
/// </summary>
/// <param name="value">valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details</param>
public void SetMinimumChange(ushort value)
{
InputPort.AnalogMinChange = value;
}
void InputPort_VersiportChange(Versiport port, VersiportEventArgs args)
{
Debug.Console(1, this, "Versiport change: {0}", args.Event);
if(args.Event == eVersiportEvent.AnalogInChange)
InputValueFeedback.FireUpdate();
if (args.Event == eVersiportEvent.AnalogMinChangeChange)
InputMinimumChangeFeedback.FireUpdate();
}
#region Bridge Linking
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = new IAnalogInputJoinMap(joinStart);
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
if (!string.IsNullOrEmpty(joinMapSerialized))
joinMap = JsonConvert.DeserializeObject<IAnalogInputJoinMap>(joinMapSerialized);
if (bridge != null)
{
bridge.AddJoinMap(Key, joinMap);
}
else
{
Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
}
try
{
Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
// Link feedback for input state
InputValueFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputValue.JoinNumber]);
InputMinimumChangeFeedback.LinkInputSig(trilist.UShortInput[joinMap.MinimumChange.JoinNumber]);
trilist.SetUShortSigAction(joinMap.MinimumChange.JoinNumber, SetMinimumChange);
}
catch (Exception e)
{
Debug.Console(1, this, "Unable to link device '{0}'. Input is null", Key);
Debug.Console(1, this, "Error: {0}", e);
}
trilist.OnlineStatusChange += (d, args) =>
{
if (!args.DeviceOnLine) return;
InputValueFeedback.FireUpdate();
InputMinimumChangeFeedback.FireUpdate();
};
}
void trilist_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
{
throw new NotImplementedException();
}
#endregion
public static Versiport GetVersiportDigitalInput(IOPortConfig dc)
{
IIOPorts ioPortDevice;
if (dc.PortDeviceKey.Equals("processor"))
{
if (!Global.ControlSystem.SupportsVersiport)
{
Debug.Console(0, "GetVersiportAnalogInput: Processor does not support Versiports");
return null;
}
ioPortDevice = Global.ControlSystem;
}
else
{
var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts;
if (ioPortDev == null)
{
Debug.Console(0, "GetVersiportAnalogInput: Device {0} is not a valid device", dc.PortDeviceKey);
return null;
}
ioPortDevice = ioPortDev;
}
if (ioPortDevice == null)
{
Debug.Console(0, "GetVersiportAnalogInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey);
return null;
}
if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts)
{
Debug.Console(0, "GetVersiportAnalogInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber);
return null;
}
if(!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput)
{
Debug.Console(0, "GetVersiportAnalogInput: Device {0} does not support AnalogInput on port {1}", dc.PortDeviceKey, dc.PortNumber);
return null;
}
return ioPortDevice.VersiPorts[dc.PortNumber];
}
}
public class GenericVersiportAbalogInputDeviceFactory : EssentialsDeviceFactory<GenericVersiportAnalogInputDevice>
{
public GenericVersiportAbalogInputDeviceFactory()
{
TypeNames = new List<string>() { "versiportanaloginput" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new Generic Versiport Device");
var props = JsonConvert.DeserializeObject<IOPortConfig>(dc.Properties.ToString());
if (props == null) return null;
var portDevice = new GenericVersiportAnalogInputDevice(dc.Key, dc.Name, GenericVersiportAnalogInputDevice.GetVersiportDigitalInput, props);
return portDevice;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.CrestronIO
{
public interface IAnalogInput
{
IntFeedback InputValueFeedback { get; }
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Wrapper class for CEN-IO-IR-104 module
/// </summary>
[Description("Wrapper class for the CEN-IO-IR-104 module")]
public class CenIoIr104Controller : CrestronGenericBaseDevice, IIROutputPorts
{
private readonly CenIoIr104 _ir104;
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
/// <param name="ir104"></param>
public CenIoIr104Controller(string key, string name, CenIoIr104 ir104)
: base(key, name, ir104)
{
_ir104 = ir104;
}
#region IDigitalInputPorts Members
/// <summary>
/// IR port collection
/// </summary>
public CrestronCollection<IROutputPort> IROutputPorts
{
get { return _ir104.IROutputPorts; }
}
/// <summary>
/// Number of relay ports property
/// </summary>
public int NumberOfIROutputPorts
{
get { return _ir104.NumberOfIROutputPorts; }
}
#endregion
}
/// <summary>
/// CEN-IO-IR-104 controller fatory
/// </summary>
public class CenIoIr104ControllerFactory : EssentialsDeviceFactory<CenIoIr104Controller>
{
/// <summary>
/// Constructor
/// </summary>
public CenIoIr104ControllerFactory()
{
TypeNames = new List<string>() { "cenioir104" };
}
/// <summary>
/// Build device CEN-IO-IR-104
/// </summary>
/// <param name="dc"></param>
/// <returns></returns>
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new CEN-IO-IR-104 Device");
var control = CommFactory.GetControlPropertiesConfig(dc);
if (control == null)
{
Debug.Console(1, "Factory failed to create a new CEN-IO-IR-104 Device, control properties not found");
return null;
}
var ipid = control.IpIdInt;
if(ipid != 0) return new CenIoIr104Controller(dc.Key, dc.Name, new CenIoIr104(ipid, Global.ControlSystem));
Debug.Console(1, "Factory failed to create a new CEN-IO-IR-104 Device using IP-ID-{0}", ipid);
return null;
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Bridges;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core.CrestronIO
{
/// <summary>
/// Represents a generic digital input deviced tied to a versiport
/// </summary>
public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput
{
public Versiport OutputPort { get; private set; }
public BoolFeedback OutputStateFeedback { get; private set; }
Func<bool> OutputStateFeedbackFunc
{
get
{
return () => OutputPort.DigitalOut;
}
}
public GenericVersiportDigitalOutputDevice(string key, string name, Func<IOPortConfig, Versiport> postActivationFunc, IOPortConfig config) :
base(key, name)
{
OutputStateFeedback = new BoolFeedback(OutputStateFeedbackFunc);
AddPostActivationAction(() =>
{
OutputPort = postActivationFunc(config);
OutputPort.Register();
if (!OutputPort.SupportsDigitalOutput)
{
Debug.Console(0, this, "Device does not support configuration as a Digital Output");
return;
}
OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput);
OutputPort.VersiportChange += OutputPort_VersiportChange;
});
}
void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args)
{
Debug.Console(1, this, "Versiport change: {0}", args.Event);
if(args.Event == eVersiportEvent.DigitalOutChange)
OutputStateFeedback.FireUpdate();
}
/// <summary>
/// Set value of the versiport digital output
/// </summary>
/// <param name="state">value to set the output to</param>
public void SetOutput(bool state)
{
if (OutputPort.SupportsDigitalOutput)
{
Debug.Console(0, this, "Passed the Check");
OutputPort.DigitalOut = state;
}
else
{
Debug.Console(0, this, "Versiport does not support Digital Output Mode");
}
}
#region Bridge Linking
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = new IDigitalOutputJoinMap(joinStart);
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
if (!string.IsNullOrEmpty(joinMapSerialized))
joinMap = JsonConvert.DeserializeObject<IDigitalOutputJoinMap>(joinMapSerialized);
if (bridge != null)
{
bridge.AddJoinMap(Key, joinMap);
}
else
{
Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
}
try
{
Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
// Link feedback for input state
OutputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.OutputState.JoinNumber]);
trilist.SetBoolSigAction(joinMap.OutputState.JoinNumber, SetOutput);
}
catch (Exception e)
{
Debug.Console(1, this, "Unable to link device '{0}'. Input is null", Key);
Debug.Console(1, this, "Error: {0}", e);
}
}
#endregion
public static Versiport GetVersiportDigitalOutput(IOPortConfig dc)
{
IIOPorts ioPortDevice;
if (dc.PortDeviceKey.Equals("processor"))
{
if (!Global.ControlSystem.SupportsVersiport)
{
Debug.Console(0, "GetVersiportDigitalOuptut: Processor does not support Versiports");
return null;
}
ioPortDevice = Global.ControlSystem;
}
else
{
var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts;
if (ioPortDev == null)
{
Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey);
return null;
}
ioPortDevice = ioPortDev;
}
if (ioPortDevice == null)
{
Debug.Console(0, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts Device", dc.PortDeviceKey);
return null;
}
if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts)
{
Debug.Console(0, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber);
}
var port = ioPortDevice.VersiPorts[dc.PortNumber];
return port;
}
}
public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory<GenericVersiportDigitalInputDevice>
{
public GenericVersiportDigitalOutputDeviceFactory()
{
TypeNames = new List<string>() { "versiportoutput" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new Generic Versiport Device");
var props = JsonConvert.DeserializeObject<IOPortConfig>(dc.Properties.ToString());
if (props == null) return null;
var portDevice = new GenericVersiportDigitalOutputDevice(dc.Key, dc.Name, GenericVersiportDigitalOutputDevice.GetVersiportDigitalOutput, props);
return portDevice;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core.CrestronIO
{
/// <summary>
/// Represents a device that provides digital input
/// </summary>
public interface IDigitalOutput
{
BoolFeedback OutputStateFeedback { get; }
void SetOutput(bool state);
}
}

View File

@@ -10,7 +10,7 @@ namespace PepperDash.Essentials.Core
/// Wrapper class for CEN-IO-RY-104 relay module
/// </summary>
[Description("Wrapper class for the CEN-IO-RY-104 relay module")]
public class CenIoRy104Controller : EssentialsDevice, IRelayPorts
public class CenIoRy104Controller : CrestronGenericBaseDevice, IRelayPorts
{
private readonly CenIoRy104 _ry104;
@@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core
/// <param name="name"></param>
/// <param name="ry104"></param>
public CenIoRy104Controller(string key, string name, CenIoRy104 ry104)
: base(key, name)
: base(key, name, ry104)
{
_ry104 = ry104;
}
@@ -62,8 +62,8 @@ namespace PepperDash.Essentials.Core
var controlPropertiesConfig = CommFactory.GetControlPropertiesConfig(dc);
if (controlPropertiesConfig == null)
{
Debug.Console(1, "Factory failed to create a new CEN-IO-RY-104 Device");
{
Debug.Console(1, "Factory failed to create a new CEN-IO-RY-104 Device, control properties not found");
return null;
}

View File

@@ -73,11 +73,14 @@ namespace PepperDash.Essentials.Core
{
//Debug.Console(1, this, " Does not require registration. Skipping");
var response = Hardware.RegisterWithLogging(Key);
if (response != eDeviceRegistrationUnRegistrationResponse.Success)
if (Hardware.Registerable && !Hardware.Registered)
{
//Debug.Console(0, this, "ERROR: Cannot register Crestron device: {0}", response);
return false;
var response = Hardware.RegisterWithLogging(Key);
if (response != eDeviceRegistrationUnRegistrationResponse.Success)
{
//Debug.Console(0, this, "ERROR: Cannot register Crestron device: {0}", response);
return false;
}
}
IsRegistered.FireUpdate();
@@ -86,7 +89,10 @@ namespace PepperDash.Essentials.Core
{
AddPostActivationAction(() =>
{
var response = Hardware.RegisterWithLogging(Key);
if (Hardware.Registerable && !Hardware.Registered)
{
var response = Hardware.RegisterWithLogging(Key);
}
IsRegistered.FireUpdate();
});

View File

@@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PepperDash.Core;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.DeviceInfo
{
public static class NetworkDeviceHelpers
{
/// <summary>
/// Event raised when ArpTable changes
/// </summary>
public static event ArpTableEventHandler ArpTableUpdated;
/// <summary>
/// Delegate called by ArpTableUpdated
/// </summary>
/// <param name="args">contains the entire ARP table and a bool to note if there was an error in retrieving the data</param>
public delegate void ArpTableEventHandler(ArpTableEventArgs args);
private static readonly char NewLineSplitter = CrestronEnvironment.NewLine.ToCharArray().First();
private static readonly string NewLine = CrestronEnvironment.NewLine;
private static readonly CCriticalSection Lock = new CCriticalSection();
/// <summary>
/// Last resolved ARP table - it is recommended to refresh the arp before using this.
/// </summary>
public static List<ArpEntry> ArpTable { get; private set; }
/// <summary>
/// Force recheck of ARP table
/// </summary>
public static void RefreshArp()
{
var error = false;
try
{
Lock.Enter();
var consoleResponse = string.Empty;
if (!CrestronConsole.SendControlSystemCommand("showarptable", ref consoleResponse)) return;
if (string.IsNullOrEmpty(consoleResponse))
{
error = true;
return;
}
ArpTable.Clear();
Debug.Console(2, "ConsoleResponse of 'showarptable' : {0}{1}", NewLine, consoleResponse);
var myLines =
consoleResponse.Split(NewLineSplitter)
.ToList()
.Where(o => (o.Contains(':') && !o.Contains("Type", StringComparison.OrdinalIgnoreCase)))
.ToList();
foreach (var line in myLines)
{
var item = line;
var seperator = item.Contains('\t') ? '\t' : ' ';
var dataPoints = item.Split(seperator);
if (dataPoints == null || dataPoints.Length < 2) continue;
var ipAddress = SanitizeIpAddress(dataPoints.First().TrimAll());
var macAddress = dataPoints.Last();
ArpTable.Add(new ArpEntry(ipAddress, macAddress));
}
}
catch (Exception ex)
{
Debug.Console(0, "Exception in \"RefreshArp\" : {0}", ex.Message);
error = true;
}
finally
{
Lock.Leave();
OnArpTableUpdated(new ArpTableEventArgs(ArpTable, error));
}
}
private static void OnArpTableUpdated(ArpTableEventArgs args)
{
if (args == null) return;
var handler = ArpTableUpdated;
if (handler == null) return;
handler.Invoke(args);
}
static NetworkDeviceHelpers()
{
ArpTable = new List<ArpEntry>();
}
/// <summary>
/// Removes leading zeros, leading whitespace, and trailing whitespace from an IPAddress string
/// </summary>
/// <param name="ipAddressIn">Ip Address to Santitize</param>
/// <returns>Sanitized Ip Address</returns>
public static string SanitizeIpAddress(string ipAddressIn)
{
try
{
var ipAddress = IPAddress.Parse(ipAddressIn.TrimStart('0'));
return ipAddress.ToString();
}
catch (Exception ex)
{
Debug.Console(0, "Unable to Santize Ip : {0}", ex.Message);
return ipAddressIn;
}
}
/// <summary>
/// Resolves a hostname by IP Address using DNS
/// </summary>
/// <param name="ipAddress">IP Address to resolve from</param>
/// <returns>Resolved Hostname - on failure to determine hostname, will return IP Address</returns>
public static string ResolveHostnameFromIp(string ipAddress)
{
try
{
var santitizedIp = SanitizeIpAddress(ipAddress);
var hostEntry = Dns.GetHostEntry(santitizedIp);
return hostEntry == null ? ipAddress : hostEntry.HostName;
}
catch (Exception ex)
{
Debug.Console(0, "Exception Resolving Hostname from IP Address : {0}", ex.Message);
return ipAddress;
}
}
/// <summary>
/// Resolves an IP Address by hostname using DNS
/// </summary>
/// <param name="hostName">Hostname to resolve from</param>
/// <returns>Resolved IP Address - on a failure to determine IP Address, will return hostname</returns>
public static string ResolveIpFromHostname(string hostName)
{
try
{
var hostEntry = Dns.GetHostEntry(hostName);
return hostEntry == null ? hostName : hostEntry.AddressList.First().ToString();
}
catch (Exception ex)
{
Debug.Console(0, "Exception Resolving IP Address from Hostname : {0}", ex.Message);
return hostName;
}
}
}
/// <summary>
/// Object to hold data about an arp entry
/// </summary>
public class ArpEntry
{
public readonly IPAddress IpAddress;
public readonly string MacAddress;
/// <summary>
/// Constructs new ArpEntry object
/// </summary>
/// <param name="ipAddress">string formatted as ipv4 address</param>
/// <param name="macAddress">mac address string - format is unimportant</param>
public ArpEntry(string ipAddress, string macAddress)
{
if (string.IsNullOrEmpty(ipAddress))
{
throw new ArgumentException("\"ipAddress\" cannot be null or empty");
}
if (string.IsNullOrEmpty(macAddress))
{
throw new ArgumentException("\"macAddress\" cannot be null or empty");
}
IpAddress = IPAddress.Parse(ipAddress.TrimStart().TrimStart('0').TrimEnd());
MacAddress = macAddress;
}
}
/// <summary>
/// Arguments passed by the ArpTableUpdated event
/// </summary>
public class ArpTableEventArgs : EventArgs
{
/// <summary>
/// The retrieved ARP Table
/// </summary>
public readonly List<ArpEntry> ArpTable;
/// <summary>
/// True if there was a problem retrieving the ARP Table
/// </summary>
public readonly bool Error;
/// <summary>
/// Constructor for ArpTableEventArgs
/// </summary>
/// <param name="arpTable">The entirety of the retrieved ARP table</param>
/// <param name="error">True of an error was encountered updating the ARP table</param>
public ArpTableEventArgs(List<ArpEntry> arpTable, bool error)
{
ArpTable = arpTable;
Error = error;
}
/// <summary>
/// Constructor for ArpTableEventArgs - assumes no error encountered in retrieving ARP Table
/// </summary>
/// <param name="arpTable">The entirety of the retrieved ARP table</param>
public ArpTableEventArgs(List<ArpEntry> arpTable)
{
ArpTable = arpTable;
Error = false;
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using PepperDash.Core;
using PepperDash.Core;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
@@ -11,14 +12,47 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
void LinkSystemMonitorToAppServer();
}
/// <summary>
/// Describes a MobileSystemController that accepts IEssentialsRoom
/// </summary>
public interface IMobileControl3 : IMobileControl
{
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
}
/// <summary>
/// Describes a MobileSystemController that accepts IEssentialsRoom
/// </summary>
public interface IMobileControl3 : IMobileControl
{
void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent);
void SendMessageObject(object o);
void AddAction(string key, object action);
void RemoveAction(string key);
void AddDeviceMessenger(IMobileControlMessenger messenger);
bool CheckForDeviceMessenger(string key);
}
/// <summary>
/// Describes a mobile control messenger
/// </summary>
public interface IMobileControlMessenger : IKeyed
{
IMobileControl3 AppServerController { get; }
string MessagePath { get; }
void RegisterWithAppServer(IMobileControl3 appServerController);
}
public interface IMobileControlResponseMessage
{
[JsonProperty("type")]
string Type { get; }
[JsonProperty("clientId")]
object ClientId { get; }
[JsonProperty("content")]
object Content { get; }
}
/// <summary>

View File

@@ -1,56 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Describes the functionality required to prompt a user to enter a password
/// </summary>
public interface IPasswordPrompt
{
/// <summary>
/// Notifies when a password is required or is entered incorrectly
/// </summary>
event EventHandler<PasswordPromptEventArgs> PasswordRequired;
/// <summary>
/// Submits the password
/// </summary>
/// <param name="password"></param>
void SubmitPassword(string password);
}
public class PasswordPromptEventArgs : EventArgs
{
/// <summary>
/// Indicates if the last submitted password was incorrect
/// </summary>
public bool LastAttemptWasIncorrect { get; private set; }
/// <summary>
/// Indicates that the login attempt has failed
/// </summary>
public bool LoginAttemptFailed { get; private set; }
/// <summary>
/// Indicates that the process was cancelled and the prompt should be dismissed
/// </summary>
public bool LoginAttemptCancelled { get; private set; }
/// <summary>
/// A message to be displayed to the user
/// </summary>
public string Message { get; private set; }
public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message)
{
LastAttemptWasIncorrect = lastAttemptIncorrect;
LoginAttemptFailed = loginFailed;
LoginAttemptCancelled = loginCancelled;
Message = message;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Describes the functionality required to prompt a user to enter a password
/// </summary>
public interface IPasswordPrompt
{
/// <summary>
/// Notifies when a password is required or is entered incorrectly
/// </summary>
event EventHandler<PasswordPromptEventArgs> PasswordRequired;
/// <summary>
/// Submits the password
/// </summary>
/// <param name="password"></param>
void SubmitPassword(string password);
}
public class PasswordPromptEventArgs : EventArgs
{
/// <summary>
/// Indicates if the last submitted password was incorrect
/// </summary>
public bool LastAttemptWasIncorrect { get; private set; }
/// <summary>
/// Indicates that the login attempt has failed
/// </summary>
public bool LoginAttemptFailed { get; private set; }
/// <summary>
/// Indicates that the process was cancelled and the prompt should be dismissed
/// </summary>
public bool LoginAttemptCancelled { get; private set; }
/// <summary>
/// A message to be displayed to the user
/// </summary>
public string Message { get; private set; }
public PasswordPromptEventArgs(bool lastAttemptIncorrect, bool loginFailed, bool loginCancelled, string message)
{
LastAttemptWasIncorrect = lastAttemptIncorrect;
LoginAttemptFailed = loginFailed;
LoginAttemptCancelled = loginCancelled;
Message = message;
}
}
}

View File

@@ -14,6 +14,7 @@ namespace PepperDash.Essentials.Core
public static class DeviceManager
{
public static event EventHandler<EventArgs> AllDevicesActivated;
public static event EventHandler<EventArgs> AllDevicesRegistered;
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
@@ -57,6 +58,8 @@ namespace PepperDash.Essentials.Core
{
try
{
OnAllDevicesRegistered();
DeviceCriticalSection.Enter();
AddDeviceEnabled = false;
// PreActivate all devices
@@ -129,6 +132,15 @@ namespace PepperDash.Essentials.Core
}
}
private static void OnAllDevicesRegistered()
{
var handler = AllDevicesRegistered;
if (handler != null)
{
handler(null, new EventArgs());
}
}
/// <summary>
/// Calls activate on all Device class items
/// </summary>
@@ -367,30 +379,28 @@ namespace PepperDash.Essentials.Core
/// Prints a list of routing inputs and outputs by device key.
/// </summary>
/// <param name="s">Device key from which to report data</param>
public static void GetRoutingPorts(string s)
{
var device = GetDeviceForKey(s);
public static void GetRoutingPorts(string s)
{
var device = GetDeviceForKey(s);
if (device == null) return;
var inputPorts = ((device as IRoutingInputs) != null) ? (device as IRoutingInputs).InputPorts : null;
var outputPorts = ((device as IRoutingOutputs) != null) ? (device as IRoutingOutputs).OutputPorts : null;
if (inputPorts != null)
{
Debug.Console(0, "Device {0} has {1} Input Ports:", s, inputPorts.Count);
foreach (var routingInputPort in inputPorts)
{
Debug.Console(0, "{0}", routingInputPort.Key);
}
}
if (outputPorts != null)
{
Debug.Console(0, "Device {0} has {1} Output Ports:", s, outputPorts.Count);
foreach (var routingOutputPort in outputPorts)
{
Debug.Console(0, "{0}", routingOutputPort.Key);
}
}
}
if (inputPorts != null)
{
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Input Ports:{2}", s, inputPorts.Count, CrestronEnvironment.NewLine);
foreach (var routingInputPort in inputPorts)
{
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingInputPort.Key, CrestronEnvironment.NewLine);
}
}
if (outputPorts == null) return;
CrestronConsole.ConsoleCommandResponse("Device {0} has {1} Output Ports:{2}", s, outputPorts.Count, CrestronEnvironment.NewLine);
foreach (var routingOutputPort in outputPorts)
{
CrestronConsole.ConsoleCommandResponse("{0}{1}", routingOutputPort.Key, CrestronEnvironment.NewLine);
}
}
/// <summary>
/// Attempts to set the debug level of a device
@@ -423,7 +433,7 @@ namespace PepperDash.Essentials.Core
if (device == null)
{
Debug.Console(0, "Unable to get device with key: {0}", deviceKey);
CrestronConsole.ConsoleCommandResponse("Unable to get device with key: {0}", deviceKey);
return;
}
@@ -435,7 +445,7 @@ namespace PepperDash.Essentials.Core
}
catch
{
Debug.Console(0, "Unable to convert setting value. Please use off/rx/tx/both");
CrestronConsole.ConsoleCommandResponse("Unable to convert setting value. Please use off/rx/tx/both");
return;
}
@@ -446,18 +456,18 @@ namespace PepperDash.Essentials.Core
var min = Convert.ToUInt32(timeout);
device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min);
Debug.Console(0, "Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min);
}
catch (Exception e)
{
Debug.Console(0, "Unable to convert minutes or settings value. Please use an integer value for minutes. Errro: {0}", e);
CrestronConsole.ConsoleCommandResponse("Unable to convert minutes or settings value. Please use an integer value for minutes. Error: {0}", e);
}
}
else
{
device.StreamDebugging.SetDebuggingWithDefaultTimeout(debugSetting);
Debug.Console(0, "Device: '{0}' debug level set to {1} for default time (30 minutes)", deviceKey, debugSetting);
CrestronConsole.ConsoleCommandResponse("Device: '{0}' debug level set to {1} for default time (30 minutes)", deviceKey, debugSetting);
}
}

View File

@@ -131,4 +131,15 @@ namespace PepperDash.Essentials.Core
/// </summary>
public string MinimumEssentialsFrameworkVersion { get; protected set; }
}
public abstract class EssentialsPluginDevelopmentDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
{
/// <summary>
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
/// </summary>
public string MinimumEssentialsFrameworkVersion { get; protected set; }
public List<string> DevelopmentEssentialsFrameworkVersions { get; protected set; }
}
}

View File

@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash_Essentials_Core.Bridges.JoinMaps;
namespace PepperDash.Essentials.Core.Devices
{
@@ -19,12 +19,11 @@ namespace PepperDash.Essentials.Core.Devices
private readonly IrOutputPortController _port;
public string[] IrCommands {get { return _port.IrFileCommands; }}
public string[] IrCommands {get { return _port.IrFileCommands; }}
public GenericIrController(string key, string name, IrOutputPortController irPort) : base(key, name)
{
_port = irPort;
if (_port == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "IR Port is null, device will not function");
@@ -71,23 +70,65 @@ namespace PepperDash.Essentials.Core.Devices
if (!string.IsNullOrEmpty(joinMapSerialized))
joinMap = JsonConvert.DeserializeObject<GenericIrControllerJoinMap>(joinMapSerialized);
for (uint i = 0; i < _port.IrFileCommands.Length; i++)
{
var cmd = _port.IrFileCommands[i];
var joinData = new JoinDataComplete(new JoinData {JoinNumber = i, JoinSpan = 1},
new JoinMetadata
{
Description = cmd,
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
if (_port.UseBridgeJoinMap)
{
Debug.Console(0, this, "Using new IR bridge join map");
joinData.SetJoinOffset(joinStart);
var bridgeJoins = joinMap.Joins.Where((kv) => _port.IrFileCommands.Any(cmd => cmd == kv.Key)).ToDictionary(kv => kv.Key);
if (bridgeJoins == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Failed to link new IR bridge join map");
return;
}
joinMap.Joins.Add(cmd,joinData);
joinMap.Joins.Clear();
trilist.SetBoolSigAction(joinData.JoinNumber, (b) => Press(cmd, b));
}
foreach (var bridgeJoin in bridgeJoins)
{
var key = bridgeJoin.Key;
var joinDataKey = bridgeJoin.Value.Key;
var joinDataValue = bridgeJoin.Value.Value;
var joinNumber = bridgeJoin.Value.Value.JoinNumber;
Debug.Console(2, this, @"bridgeJoin: Key-'{0}'
Value.Key-'{1}'
Value.JoinNumber-'{2}'
Value.Metadata.Description-'{3}'",
key,
joinDataKey,
joinNumber,
joinDataValue.Metadata.Description);
joinMap.Joins.Add(key, joinDataValue);
trilist.SetBoolSigAction(joinNumber, (b) => Press(key, b));
}
}
else
{
Debug.Console(0, this, "Using legacy IR join mapping based on available IR commands");
joinMap.Joins.Clear();
for (uint i = 0; i < _port.IrFileCommands.Length; i++)
{
var cmd = _port.IrFileCommands[i];
var joinData = new JoinDataComplete(new JoinData { JoinNumber = i, JoinSpan = 1 },
new JoinMetadata
{
Description = cmd,
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
joinData.SetJoinOffset(joinStart);
joinMap.Joins.Add(cmd, joinData);
trilist.SetBoolSigAction(joinData.JoinNumber, (b) => Press(cmd, b));
}
}
joinMap.PrintJoinMapInfo();
@@ -109,13 +150,6 @@ namespace PepperDash.Essentials.Core.Devices
}
}
public sealed class GenericIrControllerJoinMap : JoinMapBaseAdvanced
{
public GenericIrControllerJoinMap(uint joinStart) : base(joinStart)
{
}
}
public class GenericIrControllerFactory : EssentialsDeviceFactory<GenericIrController>
{
public GenericIrControllerFactory()

View File

@@ -7,25 +7,61 @@ using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Defines minimal volume control methods
/// Defines minimal volume and mute control methods
/// </summary>
public interface IBasicVolumeControls
public interface IBasicVolumeControls
{
void VolumeUp(bool pressRelease);
void VolumeDown(bool pressRelease);
void MuteToggle();
}
/// <summary>
/// Defines basic volume control methods
/// </summary>
public interface IHasVolumeControl
{
void VolumeUp(bool pressRelease);
void VolumeDown(bool pressRelease);
}
/// <summary>
/// Defines volume control methods and properties with feedback
/// </summary>
public interface IHasVolumeControlWithFeedback : IHasVolumeControl
{
void SetVolume(ushort level);
IntFeedback VolumeLevelFeedback { get; }
}
/// <summary>
/// Defines basic mute control methods
/// </summary>
public interface IHasMuteControl
{
void MuteToggle();
}
/// <summary>
/// Defines mute control methods and properties with feedback
/// </summary>
public interface IHasMuteControlWithFeedback : IHasMuteControl
{
BoolFeedback MuteFeedback { get; }
void MuteOn();
void MuteOff();
}
/// <summary>
/// Adds feedback and direct volume level set to IBasicVolumeControls
/// </summary>
public interface IBasicVolumeWithFeedback : IBasicVolumeControls
public interface IBasicVolumeWithFeedback : IBasicVolumeControls
{
void SetVolume(ushort level);
void MuteOn();
void MuteOff();
IntFeedback VolumeLevelFeedback { get; }
BoolFeedback MuteFeedback { get; }
void MuteOn();
void MuteOff();
void SetVolume(ushort level);
IntFeedback VolumeLevelFeedback { get; }
}
/// <summary>
@@ -36,6 +72,10 @@ namespace PepperDash.Essentials.Core
{
IBasicVolumeControls CurrentVolumeControls { get; }
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
void SetDefaultLevels();
bool ZeroVolumeWhenSwtichingVolumeDevices { get; }
}

View File

@@ -29,6 +29,8 @@ namespace PepperDash.Essentials.Core
public string[] IrFileCommands { get { return IrPort.AvailableStandardIRCmds(IrPortUid); } }
public bool UseBridgeJoinMap { get; private set; }
/// <summary>
/// Constructor for IrDevice base class. If a null port is provided, this class will
/// still function without trying to talk to a port.
@@ -53,9 +55,10 @@ namespace PepperDash.Essentials.Core
: base(key)
{
DriverLoaded = new BoolFeedback(() => DriverIsLoaded);
UseBridgeJoinMap = config.Properties["control"].Value<bool>("useBridgeJoinMap");
AddPostActivationAction(() =>
{
IrPort = postActivationFunc(config);
IrPort = postActivationFunc(config);
if (IrPort == null)
{
@@ -67,8 +70,8 @@ namespace PepperDash.Essentials.Core
Debug.Console(1, "*************Attempting to load IR file: {0}***************", filePath);
LoadDriver(filePath);
PrintAvailableCommands();
PrintAvailableCommands();
});
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Devices
{
/// <summary>
/// Interface for any device that is able to control it'spower and has a configurable reboot time
/// </summary>
[Obsolete("PepperDash_Essentials_Core.Devices is Deprecated - use PepperDash.Essentials.Core")]
public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback
{
/// <summary>
/// Delay between power off and power on for reboot
/// </summary>
int PowerCycleTimeMs { get;}
/// <summary>
/// Reboot outlet
/// </summary>
void PowerCycle();
}
/// <summary>
/// Interface for any device that contains a collection of IHasPowerReboot Devices
/// </summary>
[Obsolete("PepperDash_Essentials_Core.Devices is Deprecated - use PepperDash.Essentials.Core")]
public interface IHasControlledPowerOutlets : IKeyName
{
/// <summary>
/// Collection of IPduOutlets
/// </summary>
ReadOnlyDictionary<int, IHasPowerCycle> PduOutlets { get; }
}
}

View File

@@ -0,0 +1,87 @@
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Interface for any device that has a battery that can be monitored
/// </summary>
public interface IHasBatteryStats : IKeyName
{
int BatteryPercentage { get; }
int BatteryCautionThresholdPercentage { get; }
int BatteryWarningThresholdPercentage { get; }
BoolFeedback BatteryIsWarningFeedback { get; }
BoolFeedback BatteryIsCautionFeedback { get; }
BoolFeedback BatteryIsOkFeedback { get; }
IntFeedback BatteryPercentageFeedback { get; }
}
/// <summary>
/// Interface for any device that has a battery that can be monitored and the ability to charge and discharge
/// </summary>
public interface IHasBatteryCharging : IHasBatteryStats
{
BoolFeedback BatteryIsCharging { get; }
}
/// <summary>
/// Interface for any device that has multiple batteries that can be monitored
/// </summary>
public interface IHasBatteries : IKeyName
{
ReadOnlyDictionary<string, IHasBatteryStats> Batteries { get; }
}
public interface IHasBatteryStatsExtended : IHasBatteryStats
{
int InputVoltage { get; }
int OutputVoltage { get; }
int InptuCurrent { get; }
int OutputCurrent { get; }
IntFeedback InputVoltageFeedback { get; }
IntFeedback OutputVoltageFeedback { get; }
IntFeedback InputCurrentFeedback { get; }
IntFeedback OutputCurrentFeedback { get; }
}
/// <summary>
/// Interface for any device that is able to control its power, has a configurable reboot time, and has batteries that can be monitored
/// </summary>
public interface IHasPowerCycleWithBattery : IHasPowerCycle, IHasBatteryStats
{
}
/// <summary>
/// Interface for any device that is able to control it's power and has a configurable reboot time
/// </summary>
public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback
{
/// <summary>
/// Delay between power off and power on for reboot
/// </summary>
int PowerCycleTimeMs { get; }
/// <summary>
/// Reboot outlet
/// </summary>
void PowerCycle();
}
/// <summary>
/// Interface for any device that contains a collection of IHasPowerReboot Devices
/// </summary>
public interface IHasControlledPowerOutlets : IKeyName
{
/// <summary>
/// Collection of IPduOutlets
/// </summary>
ReadOnlyDictionary<int, IHasPowerCycle> PduOutlets { get; }
}
}

View File

@@ -59,7 +59,7 @@ namespace PepperDash.Essentials.Core.Devices
/// <summary>
/// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc)
/// </summary>
/// <param name="Config"></param>
/// <param name="config"></param>
protected virtual void CustomSetConfig(DeviceConfig config)
{
ConfigWriter.UpdateDeviceConfig(config);

View File

@@ -30,11 +30,40 @@ namespace PepperDash.Essentials.Core
bool _PowerIsOn;
bool _IsWarmingUp;
bool _IsCoolingDown;
protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } }
protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } }
protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } }
bool _IsCoolingDown;
protected override Func<bool> PowerIsOnFeedbackFunc
{
get
{
return () =>
{
Debug.Console(2, this, "*************************************************** Display Power is {0}", _PowerIsOn ? "on" : "off");
return _PowerIsOn;
};
} }
protected override Func<bool> IsCoolingDownFeedbackFunc
{
get
{
return () =>
{
Debug.Console(2, this, "*************************************************** {0}", _IsCoolingDown ? "Display is cooling down" : "Display has finished cooling down");
return _IsCoolingDown;
};
}
}
protected override Func<bool> IsWarmingUpFeedbackFunc
{
get
{
return () =>
{
Debug.Console(2, this, "*************************************************** {0}", _IsWarmingUp ? "Display is warming up" : "Display has finished warming up");
return _IsWarmingUp;
};
}
}
protected override Func<string> CurrentInputFeedbackFunc { get { return () => "Not Implemented"; } }
int VolumeHeldRepeatInterval = 200;
@@ -61,7 +90,7 @@ namespace PepperDash.Essentials.Core
MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted);
WarmupTime = 10000;
CooldownTime = 5000;
CooldownTime = 10000;
}
public override void PowerOn()
@@ -88,15 +117,15 @@ namespace PepperDash.Essentials.Core
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{
_IsCoolingDown = true;
_PowerIsOn = false;
PowerIsOnFeedback.InvokeFireUpdate();
IsCoolingDownFeedback.InvokeFireUpdate();
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
Debug.Console(2, this, "Cooldown timer ending");
_IsCoolingDown = false;
IsCoolingDownFeedback.InvokeFireUpdate();
IsCoolingDownFeedback.InvokeFireUpdate();
_PowerIsOn = false;
PowerIsOnFeedback.InvokeFireUpdate();
}, CooldownTime);
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
public static class StringExtensions
{
/// <summary>
/// Returns null if a string is empty, otherwise returns the string
/// </summary>
/// <param name="s">string input</param>
/// <returns>null if the string is emtpy, otherwise returns the string</returns>
public static string NullIfEmpty(this string s)
{
return string.IsNullOrEmpty(s) ? null : s;
}
/// <summary>
/// Returns null if a string is empty or made of only whitespace characters, otherwise returns the string
/// </summary>
/// <param name="s">string input</param>
/// <returns>null if the string is wempty or made of only whitespace characters, otherwise returns the string</returns>
public static string NullIfWhiteSpace(this string s)
{
return string.IsNullOrEmpty(s.Trim()) ? null : s;
}
/// <summary>
/// Returns a replacement string if the input string is empty or made of only whitespace characters, otherwise returns the input string
/// </summary>
/// <param name="s">input string</param>
/// <param name="newString">string to replace with if input string is empty or whitespace</param>
/// <returns>returns newString if s is null, emtpy, or made of whitespace characters, otherwise returns s</returns>
public static string ReplaceIfNullOrEmpty(this string s, string newString)
{
return string.IsNullOrEmpty(s) ? newString : s;
}
/// <summary>
/// Overload for Contains that allows setting an explicit String Comparison
/// </summary>
/// <param name="source">Source String</param>
/// <param name="toCheck">String to check in Source String</param>
/// <param name="comp">Comparison parameters</param>
/// <returns>true of string contains "toCheck"</returns>
public static bool Contains(this string source, string toCheck, StringComparison comp)
{
if (string.IsNullOrEmpty(source)) return false;
return source.IndexOf(toCheck, comp) >= 0;
}
/// <summary>
/// Performs TrimStart() and TrimEnd() on source string
/// </summary>
/// <param name="source">String to Trim</param>
/// <returns>Trimmed String</returns>
public static string TrimAll(this string source)
{
return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart().TrimEnd();
}
/// <summary>
/// Performs TrimStart(chars char[]) and TrimEnd(chars char[]) on source string.
/// </summary>
/// <param name="source">String to Trim</param>
/// <param name="chars">Char Array to trim from string</param>
/// <returns>Trimmed String</returns>
public static string TrimAll(this string source, char[] chars)
{
return string.IsNullOrEmpty(source) ? string.Empty : source.TrimStart(chars).TrimEnd(chars);
}
}
}

View File

@@ -172,37 +172,42 @@ namespace PepperDash.Essentials.Core
/// <summary>
/// Prints the type names and associated metadata from the FactoryMethods collection.
/// </summary>
/// <param name="command"></param>
/// <param name="filter"></param>
public static void GetDeviceFactoryTypes(string filter)
{
Dictionary<string, DeviceFactoryWrapper> types = new Dictionary<string, DeviceFactoryWrapper>();
var types = !string.IsNullOrEmpty(filter)
? FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value)
: FactoryMethods;
if (!string.IsNullOrEmpty(filter))
{
types = FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
}
else
{
types = FactoryMethods;
}
Debug.Console(0, "Device Types:");
CrestronConsole.ConsoleCommandResponse("Device Types:");
foreach (var type in types.OrderBy(t => t.Key))
{
var description = type.Value.Description;
var cType = "Not Specified by Plugin";
if(type.Value.CType != null)
if (type.Value.CType != null)
{
cType = type.Value.CType.FullName;
}
Debug.Console(0,
CrestronConsole.ConsoleCommandResponse(
@"Type: '{0}'
CType: '{1}'
Description: {2}", type.Key, cType, description);
}
}
/// <summary>
/// Returns the device factory dictionary
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
public static Dictionary<string, DeviceFactoryWrapper> GetDeviceFactoryDictionary(string filter)
{
return string.IsNullOrEmpty(filter)
? FactoryMethods
: FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
}
}
}

View File

@@ -0,0 +1,281 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using PepperDash.Core;
using Crestron.SimplSharpPro.CrestronThread;
namespace PepperDash.Essentials.Core
{
public static class FileIO
{
static CCriticalSection fileLock = new CCriticalSection();
public delegate void GotFileEventHandler(object sender, FileEventArgs e);
public static event GotFileEventHandler GotFileEvent;
/// <summary>
/// Get the full file info from a path/filename, can include wildcards.
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static FileInfo[] GetFiles(string fileName)
{
string fullFilePath = Global.FilePathPrefix + fileName;
DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath));
var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath));
Debug.Console(0, "FileIO found: {0}, {1}", files.Count(), fullFilePath);
if (files.Count() > 0)
{
return files;
}
else
{
return null;
}
}
public static FileInfo GetFile(string fileName)
{
string fullFilePath = Global.FilePathPrefix + fileName;
DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fullFilePath));
var files = dirInfo.GetFiles(Path.GetFileName(fullFilePath));
Debug.Console(0, "FileIO found: {0}, {1}", files.Count(), fullFilePath);
if (files.Count() > 0)
{
return files.FirstOrDefault();
}
else
{
return null;
}
}
/// <summary>
/// Get the data from string path/filename
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string ReadDataFromFile(string fileName)
{
try
{
return ReadDataFromFile(GetFile(fileName));
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
return "";
}
}
/// <summary>
/// Get the data with fileInfo object
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string ReadDataFromFile(FileInfo file)
{
try
{
if (fileLock.TryEnter())
{
DirectoryInfo dirInfo = new DirectoryInfo(file.DirectoryName);
Debug.Console(2, "FileIO Getting Data {0}", file.FullName);
if (File.Exists(file.FullName))
{
using (StreamReader r = new StreamReader(file.FullName))
{
return r.ReadToEnd();
}
}
else
{
Debug.Console(2, "File {0} does not exsist", file.FullName);
return "";
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "FileIO Unable to enter FileLock");
return "";
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
return "";
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
public static void ReadDataFromFileASync(string fileName)
{
try
{
ReadDataFromFileASync(GetFile(fileName));
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
}
}
public static void ReadDataFromFileASync(FileInfo file)
{
try
{
CrestronInvoke.BeginInvoke(o => _ReadDataFromFileASync(file));
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
}
}
private static void _ReadDataFromFileASync(FileInfo file)
{
string data;
try
{
if (fileLock.TryEnter())
{
DirectoryInfo dirInfo = new DirectoryInfo(file.Name);
Debug.Console(2, "FileIO Getting Data {0}", file.FullName);
if (File.Exists(file.FullName))
{
using (StreamReader r = new StreamReader(file.FullName))
{
data = r.ReadToEnd();
}
}
else
{
Debug.Console(2, "File {0} Does not exsist", file.FullName);
data = "";
}
GotFileEvent.Invoke(null, new FileEventArgs(data));
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "FileIO Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
data = "";
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="filePath"></param>
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="filePath"></param>
public static void WriteDataToFile(string data, string filePath)
{
Thread _WriteFileThread;
_WriteFileThread = new Thread((O) => _WriteFileMethod(data, Global.FilePathPrefix + "/" + filePath), null, Thread.eThreadStartOptions.CreateSuspended);
_WriteFileThread.Priority = Thread.eThreadPriority.LowestPriority;
_WriteFileThread.Start();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WriteFile Thread");
}
static object _WriteFileMethod(string data, string filePath)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write file: '{0}'", filePath);
try
{
if (fileLock.TryEnter())
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(data);
sw.Flush();
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "FileIO Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO write failed: \r{0}", e);
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
return null;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static bool FileIoUnitTest()
{
var testData = "Testing FileIO";
FileIO.WriteDataToFile(testData, "\\user\\FileIOTest.pdt");
var file = FileIO.GetFile("\\user\\*FileIOTest*");
var readData = FileIO.ReadDataFromFile(file);
Debug.Console(0, "Returned {0}", readData);
File.Delete(file.FullName);
if (testData == readData)
{
return true;
}
else
{
return false;
}
}
}
public class FileEventArgs
{
public FileEventArgs(string data) { Data = data; }
public string Data { get; private set; } // readonly
}
}

View File

@@ -148,15 +148,20 @@ namespace PepperDash.Essentials.Core.Fusion
ReadGuidFile(guidFilePath);
}
if (Room.RoomOccupancy != null)
var occupancyRoom = Room as IRoomOccupancy;
if (occupancyRoom != null)
{
if (Room.OccupancyStatusProviderIsRemote)
if (occupancyRoom.RoomOccupancy != null)
{
SetUpRemoteOccupancy();
}
else
{
SetUpLocalOccupancy();
if (occupancyRoom.OccupancyStatusProviderIsRemote)
{
SetUpRemoteOccupancy();
}
else
{
SetUpLocalOccupancy();
}
}
}
@@ -1523,10 +1528,15 @@ namespace PepperDash.Essentials.Core.Fusion
// Tie to method on occupancy object
//occSensorShutdownMinutes.OutputSig.UserObject(new Action(ushort)(b => Room.OccupancyObj.SetShutdownMinutes(b));
var occRoom = Room as IRoomOccupancy;
if (occRoom != null)
{
occRoom.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig);
occRoom.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
}
RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString);
Room.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig);
Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig);
//}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Globalization;
using Crestron.SimplSharp;
@@ -6,6 +7,7 @@ using System.Collections.Generic;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.CrestronDataStore;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DM;
using PepperDash.Core;
using PepperDash.Essentials.License;
@@ -39,7 +41,14 @@ namespace PepperDash.Essentials.Core
{
get
{
return ControlSystem.ControllerPrompt.ToLower().IndexOf("dmps") > -1;
if(ControlSystem.SystemControl != null)
{
if(ControlSystem.SystemControl.SystemControlType > 0)
{
return true;
}
}
return false;
}
}
@@ -50,7 +59,39 @@ namespace PepperDash.Essentials.Core
{
get
{
return ControlSystemIsDmpsType && ControlSystem.ControllerPrompt.ToLower().IndexOf("4k") > -1;
if(ControlSystem.SystemControl != null)
{
if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K150CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl)
{
return true;
}
}
return false;
}
}
/// <summary>
/// True when the processor type is a DMPS 4K 200/300/250/350 variant
/// </summary>
public static bool ControlSystemIsDmps4k3xxType
{
get
{
if(ControlSystem.SystemControl != null)
{
if(ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K200CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K250CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K300CSystemControl ||
ControlSystem.SystemControl.SystemControlType == eSystemControlType.Dmps34K350CSystemControl)
{
return true;
}
}
return false;
}
}
@@ -122,6 +163,38 @@ namespace PepperDash.Essentials.Core
AssemblyVersion = assemblyVersion;
}
public static bool IsRunningDevelopmentVersion(List<string> developmentVersions, string minimumVersion)
{
if (Regex.Match(AssemblyVersion, @"^(\d*).(\d*).(\d*).*").Groups[1].Value == "0")
{
Debug.Console(2, "Running Local Build. Bypassing Dependency Check.");
return true;
}
if (developmentVersions == null)
{
Debug.Console(0,
"Development Plugin does not specify a list of versions. Loading plugin may not work as expected. Checking Minumum version");
return IsRunningMinimumVersionOrHigher(minimumVersion);
}
Debug.Console(2, "Comparing running version '{0}' to minimum versions '{1}'", AssemblyVersion, developmentVersions);
var versionMatch = developmentVersions.FirstOrDefault(x => x == AssemblyVersion);
if (String.IsNullOrEmpty(versionMatch))
{
Debug.Console(0, "Essentials Build does not match any builds required for plugin load. Bypassing Plugin Load.");
return false;
}
Debug.Console(2, "Essentials Build {0} matches list of development builds", AssemblyVersion);
return IsRunningMinimumVersionOrHigher(minimumVersion);
}
/// <summary>
/// Checks to see if the running version meets or exceed the minimum specified version. For beta versions (0.xx.yy), will always return true.
/// </summary>

View File

@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
@@ -98,22 +101,22 @@ namespace PepperDash.Essentials.Core
/// </summary>
public void PrintJoinMapInfo()
{
Debug.Console(0, "{0}:\n", GetType().Name);
CrestronConsole.ConsoleCommandResponse("{0}:\n", GetType().Name);
// Get the joins of each type and print them
Debug.Console(0, "Digitals:");
CrestronConsole.ConsoleCommandResponse("Digitals:");
var digitals = Joins.Where(j => (j.Value.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
CrestronConsole.ConsoleCommandResponse("Found {0} Digital Joins", digitals.Count);
PrintJoinList(GetSortedJoins(digitals));
Debug.Console(0, "Analogs:");
CrestronConsole.ConsoleCommandResponse("Analogs:");
var analogs = Joins.Where(j => (j.Value.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
CrestronConsole.ConsoleCommandResponse("Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
Debug.Console(0, "Serials:");
CrestronConsole.ConsoleCommandResponse("Serials:");
var serials = Joins.Where(j => (j.Value.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
CrestronConsole.ConsoleCommandResponse("Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
}
@@ -136,7 +139,7 @@ namespace PepperDash.Essentials.Core
{
foreach (var join in joins)
{
Debug.Console(0,
CrestronConsole.ConsoleCommandResponse(
@"Join Number: {0} | Label: '{1}' | JoinSpan: '{2}' | Type: '{3}' | Capabilities: '{4}'",
join.Value.JoinNumber,
join.Value.Label,
@@ -193,19 +196,6 @@ namespace PepperDash.Essentials.Core
protected void AddJoins(Type type)
{
// Add all the JoinDataComplete properties to the Joins Dictionary and pass in the offset
//Joins = this.GetType()
// .GetCType()
// .GetFields(BindingFlags.Public | BindingFlags.Instance)
// .Where(field => field.IsDefined(typeof(JoinNameAttribute), true))
// .Select(field => (JoinDataComplete)field.GetValue(this))
// .ToDictionary(join => join.GetNameAttribute(), join =>
// {
// join.SetJoinOffset(_joinOffset);
// return join;
// });
//type = this.GetType(); <- this wasn't working because 'this' was always the base class, never the derived class
var fields =
type.GetCType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
@@ -219,7 +209,7 @@ namespace PepperDash.Essentials.Core
if (value == null)
{
Debug.Console(0, "Unable to caset base class to {0}", type.Name);
Debug.Console(0, "Unable to cast base class to {0}", type.Name);
continue;
}
@@ -244,23 +234,69 @@ namespace PepperDash.Essentials.Core
/// </summary>
public void PrintJoinMapInfo()
{
Debug.Console(0, "{0}:\n", GetType().Name);
var sb = JoinmapStringBuilder();
CrestronConsole.ConsoleCommandResponse(sb.ToString());
}
private StringBuilder JoinmapStringBuilder()
{
var sb = new StringBuilder();
// Get the joins of each type and print them
Debug.Console(0, "Digitals:");
var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
PrintJoinList(GetSortedJoins(digitals));
sb.AppendLine(String.Format("# {0}", GetType().Name));
sb.AppendLine();
sb.AppendLine("## Digitals");
sb.AppendLine();
// Get the joins of each type and print them
var digitals =
Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital)
.ToDictionary(j => j.Key, j => j.Value);
var digitalSb = AppendJoinList(GetSortedJoins(digitals));
digitalSb.AppendLine("## Analogs");
digitalSb.AppendLine();
Debug.Console(0, "Analogs:");
var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
Debug.Console(0, "Serials:");
var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
var analogs =
Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog)
.ToDictionary(j => j.Key, j => j.Value);
var analogSb = AppendJoinList(GetSortedJoins(analogs));
analogSb.AppendLine("## Serials");
analogSb.AppendLine();
var serials =
Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial)
.ToDictionary(j => j.Key, j => j.Value);
var serialSb = AppendJoinList(GetSortedJoins(serials));
sb.EnsureCapacity(sb.Length + digitalSb.Length + analogSb.Length + serialSb.Length);
sb.Append(digitalSb).Append(analogSb).Append(serialSb);
return sb;
}
/// <summary>
/// Prints the join information to console
/// </summary>
public void MarkdownJoinMapInfo(string deviceKey, string bridgeKey)
{
var pluginType = GetType().Name;
CrestronConsole.ConsoleCommandResponse("{0}:\n", pluginType);
WriteJoinmapMarkdown(JoinmapStringBuilder(), pluginType, bridgeKey, deviceKey);
}
private static void WriteJoinmapMarkdown(StringBuilder stringBuilder, string pluginType, string bridgeKey, string deviceKey)
{
var fileName = String.Format("{0}{1}{2}__{3}__{4}.md", Global.FilePathPrefix, "joinMaps/", pluginType, bridgeKey, deviceKey);
using (var sw = new StreamWriter(fileName))
{
sw.WriteLine(stringBuilder.ToString());
CrestronConsole.ConsoleCommandResponse("Joinmap Readme generated and written to {0}", fileName);
}
}
@@ -269,7 +305,7 @@ namespace PepperDash.Essentials.Core
/// </summary>
/// <param name="joins"></param>
/// <returns></returns>
List<KeyValuePair<string, JoinDataComplete>> GetSortedJoins(Dictionary<string, JoinDataComplete> joins)
static List<KeyValuePair<string, JoinDataComplete>> GetSortedJoins(Dictionary<string, JoinDataComplete> joins)
{
var sortedJoins = joins.ToList();
@@ -278,18 +314,38 @@ namespace PepperDash.Essentials.Core
return sortedJoins;
}
void PrintJoinList(List<KeyValuePair<string, JoinDataComplete>> joins)
static StringBuilder AppendJoinList(List<KeyValuePair<string, JoinDataComplete>> joins)
{
var sb = new StringBuilder();
const string stringFormatter = "| {0} | {1} | {2} | {3} | {4} |";
const int joinNumberLen = 11;
const int joinSpanLen = 9;
const int typeLen = 19;
const int capabilitiesLen = 12;
var descriptionLen = (from @join in joins select @join.Value into j select j.Metadata.Description.Length).Concat(new[] {11}).Max();
//build header
sb.AppendLine(String.Format(stringFormatter,
String.Format("Join Number").PadRight(joinNumberLen, ' '),
String.Format("Join Span").PadRight(joinSpanLen, ' '),
String.Format("Description").PadRight(descriptionLen, ' '),
String.Format("Type").PadRight(typeLen, ' '),
String.Format("Capabilities").PadRight(capabilitiesLen, ' ')));
//build table seperator
sb.AppendLine(String.Format(stringFormatter,
new String('-', joinNumberLen),
new String('-', joinSpanLen),
new String('-', descriptionLen),
new String('-', typeLen),
new String('-', capabilitiesLen)));
foreach (var join in joins)
{
Debug.Console(0,
@"Join Number: {0} | JoinSpan: '{1}' | Description: '{2}' | Type: '{3}' | Capabilities: '{4}'",
join.Value.JoinNumber,
join.Value.JoinSpan,
String.IsNullOrEmpty(join.Value.AttributeName) ? join.Value.Metadata.Label : join.Value.AttributeName,
join.Value.Metadata.JoinType.ToString(),
join.Value.Metadata.JoinCapabilities.ToString());
sb.AppendLine(join.Value.GetMarkdownFormattedData(stringFormatter, descriptionLen));
}
sb.AppendLine();
return sb;
}
/// <summary>
@@ -300,16 +356,18 @@ namespace PepperDash.Essentials.Core
{
foreach (var customJoinData in joinData)
{
var join = Joins[customJoinData.Key];
JoinDataComplete join;
if (!Joins.TryGetValue(customJoinData.Key, out join))
{
Debug.Console(2, "No matching key found in join map for: '{0}'", customJoinData.Key);
continue;
}
if (join != null)
{
join.SetCustomJoinData(customJoinData.Value);
}
else
{
Debug.Console(2, "No matching key found in join map for: '{0}'", customJoinData.Key);
}
}
PrintJoinMapInfo();
@@ -458,6 +516,64 @@ namespace PepperDash.Essentials.Core
Metadata = metadata;
}
public string GetMarkdownFormattedData(string stringFormatter, int descriptionLen)
{
//Fixed Width Headers
var joinNumberLen = String.Format("Join Number").Length;
var joinSpanLen = String.Format("Join Span").Length;
var typeLen = String.Format("AnalogDigitalSerial").Length;
var capabilitiesLen = String.Format("ToFromFusion").Length;
//Track which one failed, if it did
const string placeholder = "unknown";
var dataArray = new Dictionary<string, string>
{
{"joinNumber", placeholder.PadRight(joinNumberLen, ' ')},
{"joinSpan", placeholder.PadRight(joinSpanLen, ' ')},
{"description", placeholder.PadRight(descriptionLen, ' ')},
{"joinType", placeholder.PadRight(typeLen, ' ')},
{"capabilities", placeholder.PadRight(capabilitiesLen, ' ')}
};
try
{
dataArray["joinNumber"] = String.Format("{0}", JoinNumber.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinNumberLen, ' ');
dataArray["joinSpan"] = String.Format("{0}", JoinSpan.ToString(CultureInfo.InvariantCulture).ReplaceIfNullOrEmpty(placeholder)).PadRight(joinSpanLen, ' ');
dataArray["description"] = String.Format("{0}", Metadata.Description.ReplaceIfNullOrEmpty(placeholder)).PadRight(descriptionLen, ' ');
dataArray["joinType"] = String.Format("{0}", Metadata.JoinType.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(typeLen, ' ');
dataArray["capabilities"] = String.Format("{0}", Metadata.JoinCapabilities.ToString().ReplaceIfNullOrEmpty(placeholder)).PadRight(capabilitiesLen, ' ');
return String.Format(stringFormatter,
dataArray["joinNumber"],
dataArray["joinSpan"],
dataArray["description"],
dataArray["joinType"],
dataArray["capabilities"]);
}
catch (Exception e)
{
//Don't Throw - we don't want to kill the system if this falls over - it's not mission critical. Print the error, use placeholder data
var errorKey = string.Empty;
foreach (var item in dataArray)
{
if (item.Value.TrimEnd() == placeholder) continue;
errorKey = item.Key;
break;
}
Debug.Console(0, "Unable to decode join metadata {1}- {0}", e.Message, !String.IsNullOrEmpty(errorKey) ? (' ' + errorKey) : String.Empty);
return String.Format(stringFormatter,
dataArray["joinNumber"],
dataArray["joinSpan"],
dataArray["description"],
dataArray["joinType"],
dataArray["capabilities"]);
}
}
/// <summary>
/// Sets the join offset value
/// </summary>

View File

@@ -92,50 +92,47 @@ namespace PepperDash.Essentials.Core.Lighting
return LinkLightingToApi(lightingDevice, trilist, joinMap);
}
protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap)
{
protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap)
{
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString());
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
// GenericLighitng Actions & FeedBack
trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u]));
Debug.Console(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString());
var sceneIndex = 0;
foreach (var scene in lightingDevice.LightingScenes)
{
var index = sceneIndex;
// GenericLighitng Actions & FeedBack
trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u]));
trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index]));
scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]);
trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
var sceneIndex = 0;
foreach (var scene in lightingDevice.LightingScenes)
{
var index = sceneIndex;
sceneIndex++;
}
trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index]));
scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]);
trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
trilist.OnlineStatusChange += (sender, args) =>
{
if (!args.DeviceOnLine) return;
sceneIndex++;
}
sceneIndex = 0;
foreach (var scene in lightingDevice.LightingScenes)
{
var index = sceneIndex;
trilist.OnlineStatusChange += (sender, args) =>
{
if (!args.DeviceOnLine) return;
trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
scene.IsActiveFeedback.FireUpdate();
sceneIndex = 0;
foreach (var scene in lightingDevice.LightingScenes)
{
var index = sceneIndex;
trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
scene.IsActiveFeedback.FireUpdate();
sceneIndex++;
}
};
return joinMap;
}
sceneIndex++;
}
};
return joinMap;
}
}
public class LightingScene

View File

@@ -43,7 +43,20 @@ namespace PepperDash.Essentials.Core.Monitoring
public StringFeedback UptimeFeedback { get; set; }
public StringFeedback LastStartFeedback { get; set; }
public SystemMonitorController(string key)
public BoolFeedback IsApplianceFeedback { get; protected set; }
private bool _isApplianceFb
{
get { return CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance; }
}
public BoolFeedback IsServerFeedback { get; protected set; }
private bool _isServerFb
{
get { return CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; }
}
public SystemMonitorController(string key)
: base(key)
{
Debug.Console(2, this, "Adding SystemMonitorController.");
@@ -63,6 +76,9 @@ namespace PepperDash.Essentials.Core.Monitoring
UptimeFeedback = new StringFeedback(() => _uptime);
LastStartFeedback = new StringFeedback(()=> _lastStart);
IsApplianceFeedback = new BoolFeedback(() => _isApplianceFb);
IsServerFeedback = new BoolFeedback(() => _isServerFb);
ProgramStatusFeedbackCollection = new Dictionary<uint, ProgramStatusFeedbacks>();
foreach (var prog in SystemMonitor.ProgramCollection)
@@ -123,6 +139,26 @@ namespace PepperDash.Essentials.Core.Monitoring
_uptime = uptimeRaw.Substring(forIndex + 4);
}
private static void ProcessorReboot()
{
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
var response = string.Empty;
CrestronConsole.SendControlSystemCommand("reboot", ref response);
}
private static void ProgramReset(uint index)
{
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
if (index <= 0 || index > 10) return;
var cmd = string.Format("progreset -p:{0}", index);
var response = string.Empty;
CrestronConsole.SendControlSystemCommand(cmd, ref response);
}
private void CrestronEnvironmentOnEthernetEventHandler(EthernetEventArgs ethernetEventArgs)
{
if (ethernetEventArgs.EthernetEventType != eEthernetEventType.LinkUp) return;
@@ -185,6 +221,9 @@ namespace PepperDash.Essentials.Core.Monitoring
SerialNumberFeedback.FireUpdate();
ModelFeedback.FireUpdate();
IsApplianceFeedback.FireUpdate();
IsServerFeedback.FireUpdate();
OnSystemMonitorPropertiesChanged();
}
@@ -237,6 +276,11 @@ namespace PepperDash.Essentials.Core.Monitoring
UptimeFeedback.LinkInputSig(trilist.StringInput[joinMap.Uptime.JoinNumber]);
LastStartFeedback.LinkInputSig(trilist.StringInput[joinMap.LastBoot.JoinNumber]);
trilist.SetSigHeldAction(joinMap.ProcessorReboot.JoinNumber, 10000, ProcessorReboot);
IsApplianceFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsAppliance.JoinNumber]);
IsServerFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsServer.JoinNumber]);
// iterate the program status feedback collection and map all the joins
LinkProgramInfoJoins(this, trilist, joinMap);
@@ -301,11 +345,13 @@ namespace PepperDash.Essentials.Core.Monitoring
p.Value.AggregatedProgramInfoFeedback.LinkInputSig(
trilist.StringInput[programSlotJoinStart + joinMap.AggregatedProgramInfo.JoinNumber]);
trilist.SetSigHeldAction(programSlotJoinStart + joinMap.ProgramReset.JoinNumber, 10000, () => ProgramReset(programNumber));
programSlotJoinStart = programSlotJoinStart + joinMap.ProgramOffsetJoin.JoinSpan;
}
}
}
//// Sets the time zone
//// Sets the time zone
//public void SetTimeZone(int timeZone)
//{
// SystemMonitor.TimeZoneInformation.TimeZoneNumber = timeZone;
@@ -517,11 +563,11 @@ namespace PepperDash.Essentials.Core.Monitoring
ProgramUnregisteredFeedback =
new BoolFeedback(() => Program.RegistrationState == eProgramRegistrationState.Unregister);
ProgramUnregisteredFeedback.FireUpdate();
ProgramNameFeedback = new StringFeedback(() => ProgramInfo.ProgramFile);
ProgramNameFeedback = new StringFeedback(() => ProgramInfo.ProgramFile);
CrestronDataBaseVersionFeedback = new StringFeedback(() => ProgramInfo.CrestronDb);
EnvironmentVersionFeedback = new StringFeedback(() => ProgramInfo.Environment);
ProgramCompileTimeFeedback = new StringFeedback(() => ProgramInfo.CompileTime);
CrestronDataBaseVersionFeedback = new StringFeedback(() => ProgramInfo.CrestronDb);
EnvironmentVersionFeedback = new StringFeedback(() => ProgramInfo.Environment);
AggregatedProgramInfoFeedback = new StringFeedback(() => JsonConvert.SerializeObject(ProgramInfo));
GetProgramInfo();
@@ -574,9 +620,9 @@ namespace PepperDash.Essentials.Core.Monitoring
// Assume no valid program info. Constructing a new object will wipe all properties
ProgramInfo = new ProgramInfo(Program.Number)
{
OperatingState = Program.OperatingState,
OperatingState = Program.OperatingState,
RegistrationState = Program.RegistrationState
};
};
UpdateFeedbacks();
@@ -593,13 +639,20 @@ namespace PepperDash.Essentials.Core.Monitoring
if (ProgramInfo.ProgramFile.Contains(".dll"))
{
// SSP Program
// SSP Program
ProgramInfo.FriendlyName = ParseConsoleData(response, "Friendly Name", ": ", "\n");
ProgramInfo.ApplicationName = ParseConsoleData(response, "Application Name", ": ", "\n");
ProgramInfo.ProgramTool = ParseConsoleData(response, "Program Tool", ": ", "\n");
ProgramInfo.MinFirmwareVersion = ParseConsoleData(response, "Min Firmware Version", ": ",
"\n");
ProgramInfo.PlugInVersion = ParseConsoleData(response, "PlugInVersion", ": ", "\n");
ProgramInfo.ProgramFile += string.Format(" {0}.{1}.{2}",
ProgramInfo.CompilerRevisionInfo.Major,
ProgramInfo.CompilerRevisionInfo.Minor,
ProgramInfo.CompilerRevisionInfo.Build);
ProgramInfo.Environment = ProgramInfo.ProgramTool;
}
else if (ProgramInfo.ProgramFile.Contains(".smw"))
{
@@ -690,6 +743,15 @@ namespace PepperDash.Essentials.Core.Monitoring
[JsonProperty("compilerRevision")]
public string CompilerRevision { get; set; }
[JsonIgnore]
public Version CompilerRevisionInfo
{
get
{
return new Version(CompilerRevision);
}
}
[JsonProperty("compileTime")]
public string CompileTime { get; set; }
@@ -730,7 +792,7 @@ namespace PepperDash.Essentials.Core.Monitoring
ProgramFile = "";
FriendlyName = "";
CompilerRevision = "";
CompileTime = "";
CompileTime = "";
Include4Dat = "";
SystemName = "";

View File

@@ -85,18 +85,32 @@ namespace PepperDash.Essentials.Core
{
if (_partitionSensor.IsOnline == false) return;
Debug.Console(1, this, "Attempting to apply settings to sensor from config");
// Default to enable
_partitionSensor.Enable.BoolValue = true;
if (PropertiesConfig.Sensitivity != null)
{
Debug.Console(1, this, "Sensitivity found, attempting to set value '{0}' from config",
PropertiesConfig.Sensitivity);
_partitionSensor.Sensitivity.UShortValue = (ushort) PropertiesConfig.Sensitivity;
}
else
{
Debug.Console(1, this, "Sensitivity null, no value specified in config");
}
Debug.Console(1, this, "Attempting to apply settings to sensor from config");
if (PropertiesConfig.Sensitivity != null)
{
Debug.Console(1, this, "Sensitivity found, attempting to set value '{0}' from config",
PropertiesConfig.Sensitivity);
_partitionSensor.Sensitivity.UShortValue = (ushort)PropertiesConfig.Sensitivity;
}
else
{
Debug.Console(1, this, "Sensitivity null, no value specified in config");
}
if (PropertiesConfig.Enable != null)
{
Debug.Console(1, this, "Enable found, attempting to set value '{0}' from config",
PropertiesConfig.Enable);
_partitionSensor.Enable.BoolValue = (bool)PropertiesConfig.Enable;
}
else
{
Debug.Console(1, this, "Enable null, no value specified in config");
}
}

View File

@@ -16,6 +16,9 @@ namespace PepperDash_Essentials_Core.PartitionSensor
/// The sensitivity range shall be between 1(lowest) to 10 (highest).
/// </remarks>
[JsonProperty("sensitivity")]
public ushort? Sensitivity { get; set; }
public ushort? Sensitivity { get; set; }
[JsonProperty("enable")]
public bool? Enable { get; set; }
}
}

View File

@@ -83,7 +83,7 @@
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.42.30563, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.2.1.30543, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
</Reference>
@@ -92,6 +92,10 @@
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SimplSharpCWSHelperInterface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.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>
@@ -123,6 +127,11 @@
<Compile Include="Bridges\IBridge.cs" />
<Compile Include="Bridges\JoinMaps\AirMediaControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\AppleTvJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\GenericIrControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\HdPsXxxControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\IAnalogInputJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\IDigitalOutputJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\PduJoinMapBase.cs" />
<Compile Include="Bridges\JoinMaps\C2nRthsControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\CameraControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\CenOdtOccupancySensorBaseJoinMap.cs" />
@@ -176,17 +185,44 @@
</Compile>
<Compile Include="Crestron IO\Cards\CenCi33Controller.cs" />
<Compile Include="Crestron IO\Cards\InternalCardCageController.cs" />
<Compile Include="Crestron IO\CenIoCom\CenIoComController.cs" />
<Compile Include="Crestron IO\DinCenCn\DinCenCnController.cs" />
<Compile Include="Crestron IO\DinCenCn\IHasCresnetBranches.cs" />
<Compile Include="Crestron IO\DinIo8\DinIo8Controller.cs" />
<Compile Include="Crestron IO\Inputs\CenIoDigIn104Controller.cs" />
<Compile Include="Crestron IO\Inputs\GenericVersiportAnalogInputDevice.cs" />
<Compile Include="Crestron IO\Inputs\GenericDigitalInputDevice.cs" />
<Compile Include="Crestron IO\Inputs\GenericVersiportInputDevice.cs" />
<Compile Include="Crestron IO\Inputs\IAnalogInput.cs" />
<Compile Include="Crestron IO\Inputs\IDigitalInput.cs" />
<Compile Include="Crestron IO\IOPortConfig.cs" />
<Compile Include="Crestron IO\Ir\CenIoIr104Controller.cs" />
<Compile Include="Crestron IO\Outputs\GenericVersiportOutputDevice.cs" />
<Compile Include="Crestron IO\Outputs\IDigitalOutput.cs" />
<Compile Include="Crestron IO\Relay\CenIoRy104Controller.cs" />
<Compile Include="Crestron IO\Relay\GenericRelayDevice.cs" />
<Compile Include="Crestron IO\Relay\ISwitchedOutput.cs" />
<Compile Include="Crestron IO\StatusSign\StatusSignController.cs" />
<Compile Include="Device Info\NetworkDeviceHelpers.cs" />
<Compile Include="Devices\PowerInterfaces.cs" />
<Compile Include="Web\RequestHandlers\AppDebugRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\GetFeedbacksForDeviceRequestHandler.cs" />
<Compile Include="Web\EssentialsWebApiHelpers.cs" />
<Compile Include="Web\RequestHandlers\GetTypesByFilterRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\GetJoinMapForDeviceKeyRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\DevListRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\DevPropsRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\DevJsonRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\SetDeviceStreamDebugRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\DisableAllStreamDebugRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\ShowConfigRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\GetTypesRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\GetJoinMapForBridgeKeyRequestHandler.cs" />
<Compile Include="Web\EssemtialsWebApi.cs" />
<Compile Include="Web\EssentialsWebApiFactory.cs" />
<Compile Include="Web\EssentialsWebApiPropertiesConfig.cs" />
<Compile Include="Web\RequestHandlers\ReportVersionsRequestHandler.cs" />
<Compile Include="Device Info\DeviceInfo.cs" />
<Compile Include="Device Info\DeviceInfoEventArgs.cs" />
<Compile Include="Device Info\IDeviceInfoProvider.cs" />
@@ -203,6 +239,7 @@
<Compile Include="Devices\IReconfigurableDevice.cs" />
<Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\PduInterfaces.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\IPasswordPrompt.cs" />
@@ -215,6 +252,7 @@
<Compile Include="DeviceTypeInterfaces\IHasPhoneDialing.cs" />
<Compile Include="DeviceTypeInterfaces\IMobileControl.cs" />
<Compile Include="Extensions\JsonExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Factory\DeviceFactory.cs" />
<Compile Include="Factory\IDeviceFactory.cs" />
<Compile Include="Factory\ReadyEventArgs.cs" />
@@ -224,6 +262,7 @@
<Compile Include="Feedbacks\IntFeedback.cs" />
<Compile Include="Feedbacks\SerialFeedback.cs" />
<Compile Include="Feedbacks\StringFeedback.cs" />
<Compile Include="File\FileIO.cs" />
<Compile Include="Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
<Compile Include="Fusion\FusionCustomPropertiesBridge.cs" />
<Compile Include="Fusion\FusionEventHandlers.cs" />
@@ -335,7 +374,9 @@
<Compile Include="Feedbacks\BoolFeedbackPulseExtender.cs" />
<Compile Include="Routing\RoutingPortNames.cs" />
<Compile Include="Routing\TieLineConfig.cs" />
<Compile Include="Secrets\CrestronSecretsProvider.cs" />
<Compile Include="Secrets\CrestronGlobalSecretsProvider.cs" />
<Compile Include="Secrets\CrestronLocalSecretsProvider.cs" />
<Compile Include="Secrets\CrestronSecret.cs" />
<Compile Include="Secrets\Interfaces.cs" />
<Compile Include="Secrets\SecretsManager.cs" />
<Compile Include="Secrets\SecretsPropertiesConfig.cs" />
@@ -360,6 +401,7 @@
<Compile Include="UI PageManagers\SinglePageManager.cs" />
<Compile Include="UI PageManagers\PageManager.cs" />
<Compile Include="UI PageManagers\SetTopBoxTwoPanelPageManager.cs" />
<Compile Include="UI\TouchpanelBase.cs" />
<Compile Include="Utilities\ActionSequence.cs" />
<Compile Include="VideoStatus\VideoStatusOutputs.cs" />
<Compile Include="Crestron\CrestronGenericBaseDevice.cs" />

View File

@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Crestron_0020Web_0020Server/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Web/@EntryIndexedValue">False</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using PepperDash.Core;
@@ -15,5 +16,10 @@ namespace PepperDash.Essentials.Core
}
public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory
{
List<string> DevelopmentEssentialsFrameworkVersions { get; }
}
}
}

View File

@@ -194,13 +194,13 @@ namespace PepperDash.Essentials
/// <param name="command"></param>
public static void ReportAssemblyVersions(string command)
{
Debug.Console(0, "Loaded Assemblies:");
CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine);
foreach (var assembly in LoadedAssemblies)
{
Debug.Console(0, "{0} Version: {1}", assembly.Name, assembly.Version);
CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
}
}
/// <summary>
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
/// </summary>
@@ -425,7 +425,11 @@ namespace PepperDash.Essentials
/// <param name="loadedAssembly"></param>
static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
{
var passed = Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
var developmentPlugin = plugin as IPluginDevelopmentDeviceFactory;
var passed = developmentPlugin != null ? Global.IsRunningDevelopmentVersion
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
: Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
if (!passed)
{

View File

@@ -1,5 +1,6 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharpPro.CrestronThread;
using PepperDash.Core;
@@ -187,9 +188,20 @@ namespace PepperDash.Essentials.Core.Queues
if (_delayEnabled)
Thread.Sleep(_delayTime);
}
catch (System.Threading.ThreadAbortException)
{
//swallowing this exception, as it should only happen on shut down
}
catch (Exception ex)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Caught an exception in the Queue {0}\r{1}\r{2}", ex.Message, ex.InnerException, ex.StackTrace);
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Caught an exception in the Queue: {1}:{0}", ex.Message, ex);
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.StackTrace);
if (ex.InnerException != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "---\r\n{0}", ex.InnerException.Message);
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.InnerException.StackTrace);
}
}
}
else _waitHandle.Wait();
@@ -202,7 +214,7 @@ namespace PepperDash.Essentials.Core.Queues
{
if (Disposed)
{
Debug.Console(1, this, "I've been disposed so you can't enqueue any messages. Are you trying to dispatch a message while the program is stopping?");
Debug.Console(1, this, "Queue has been disposed. Enqueuing messages not allowed while program is stopping.");
return;
}
@@ -446,7 +458,14 @@ namespace PepperDash_Essentials_Core.Queues
}
catch (Exception ex)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Caught an exception in the Queue {0}\r{1}\r{2}", ex.Message, ex.InnerException, ex.StackTrace);
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Caught an exception in the Queue {0}", ex.Message);
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.StackTrace);
if (ex.InnerException != null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Caught an exception in the Queue {0}", ex.InnerException.Message);
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.InnerException.StackTrace);
}
}
}
else _waitHandle.Wait();

View File

@@ -38,7 +38,7 @@ namespace PepperDash.Essentials.Core
ScheduledEventGroup FeatureEventGroup;
public IEssentialsRoom Room { get; private set; }
public IRoomOccupancy Room { get; private set; }
private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom;
@@ -84,7 +84,7 @@ namespace PepperDash.Essentials.Core
/// </summary>
void SetUpDevice()
{
Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IEssentialsRoom;
Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IRoomOccupancy;
if (Room != null)
{
@@ -235,12 +235,23 @@ namespace PepperDash.Essentials.Core
if (FeatureEnabled)
{
// Check room power state first
if (!Room.OnFeedback.BoolValue)
{
Debug.Console(1, this, "Powering Room on to default source");
Room.RunDefaultPresentRoute();
var essentialsRoom = Room as IEssentialsRoom;
if (essentialsRoom != null) {
if (!essentialsRoom.OnFeedback.BoolValue)
{
Debug.Console(1, this, "Powering Room on to default source");
var defaultRouteRoom = Room as IRunDefaultPresentRoute;
if (defaultRouteRoom != null)
{
defaultRouteRoom.RunDefaultPresentRoute();
}
}
}
// Check room power state first
}
}
}

View File

@@ -35,7 +35,7 @@ namespace PepperDash.Essentials.Core
public BoolFeedback IsWarmingUpFeedback { get; private set; }
public BoolFeedback IsCoolingDownFeedback { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; protected set; }
public bool OccupancyStatusProviderIsRemote { get; private set; }
@@ -343,7 +343,7 @@ namespace PepperDash.Essentials.Core
void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false && AllowVacancyTimerToStart())
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
@@ -362,6 +362,15 @@ namespace PepperDash.Essentials.Core
/// </summary>
/// <param name="o"></param>
public abstract void RoomVacatedForTimeoutPeriod(object o);
/// <summary>
/// Allow the vacancy event from an occupancy sensor to turn the room off.
/// </summary>
/// <returns>If the timer should be allowed. Defaults to true</returns>
protected virtual bool AllowVacancyTimerToStart()
{
return true;
}
}
/// <summary>

View File

@@ -17,15 +17,10 @@ namespace PepperDash.Essentials.Core
/// </summary>
public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls
{
BoolFeedback OnFeedback { get; }
event EventHandler<EventArgs> RoomOccupancyIsSet;
BoolFeedback OnFeedback { get; }
BoolFeedback IsWarmingUpFeedback { get; }
BoolFeedback IsCoolingDownFeedback { get; }
IOccupancyStatusProvider RoomOccupancy { get; }
bool OccupancyStatusProviderIsRemote { get; }
BoolFeedback IsCoolingDownFeedback { get; }
bool IsMobileControlEnabled { get; }
IMobileControlRoomBridge MobileControlRoomBridge { get; }
@@ -35,31 +30,16 @@ namespace PepperDash.Essentials.Core
SecondsCountdownTimer ShutdownPromptTimer { get; }
int ShutdownPromptSeconds { get; }
int ShutdownVacancySeconds { get; }
eShutdownType ShutdownType { get; }
EssentialsRoomEmergencyBase Emergency { get; }
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
eShutdownType ShutdownType { get; }
string LogoUrlLightBkgnd { get; }
string LogoUrlDarkBkgnd { get; }
eVacancyMode VacancyMode { get; }
void StartShutdown(eShutdownType type);
bool ZeroVolumeWhenSwtichingVolumeDevices { get; }
void Shutdown();
void StartShutdown(eShutdownType type);
void StartRoomVacancyTimer(eVacancyMode mode);
void Shutdown();
void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes);
void PowerOnToDefaultOrLastSource();
void SetDefaultLevels();
void RoomVacatedForTimeoutPeriod(object o);
void PowerOnToDefaultOrLastSource();
}
}

View File

@@ -41,7 +41,6 @@ namespace PepperDash.Essentials.Core
void RunRouteAction(string routeKey, string sourceListKey);
void RunRouteAction(string routeKey, string sourceListKey, Action successCallback);
}
/// <summary>
@@ -78,4 +77,30 @@ namespace PepperDash.Essentials.Core
bool HasEnvironmentalControlDevices { get; }
}
public interface IRoomOccupancy:IKeyed
{
IOccupancyStatusProvider RoomOccupancy { get; }
bool OccupancyStatusProviderIsRemote { get; }
void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes);
void RoomVacatedForTimeoutPeriod(object o);
void StartRoomVacancyTimer(eVacancyMode mode);
eVacancyMode VacancyMode { get; }
event EventHandler<EventArgs> RoomOccupancyIsSet;
}
public interface IEmergency
{
EssentialsRoomEmergencyBase Emergency { get; }
}
public interface IMicrophonePrivacy
{
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
}
}

View File

@@ -1,344 +1,425 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DM;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Extensions added to any IRoutingInputs classes to provide discovery-based routing
/// on those destinations.
/// </summary>
public static class IRoutingInputsExtensions
{
/// <summary>
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
/// in RouteDescriptorCollection.DefaultCollection
/// </summary>
public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
{
destination.ReleaseRoute();
if (source == null) return;
var newRoute = destination.GetRouteToSource(source, signalType);
if (newRoute == null) return;
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
Debug.Console(2, destination, "Executing full route");
newRoute.ExecuteRoutes();
}
/// <summary>
/// Will release the existing route on the destination, if it is found in
/// RouteDescriptorCollection.DefaultCollection
/// </summary>
/// <param name="destination"></param>
public static void ReleaseRoute(this IRoutingSink destination)
{
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
if (current != null)
{
Debug.Console(1, destination, "Releasing current route: {0}", current.Source.Key);
current.ReleaseRoutes();
}
}
/// <summary>
/// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
/// Routes of type AudioVideo will be built as two separate routes, audio and video. If
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
/// of an audio/video route are discovered a route descriptor is returned. If no route is
/// discovered, then null is returned
/// </summary>
public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
{
var routeDescr = new RouteDescriptor(source, destination, signalType);
// if it's a single signal type, find the route
if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video))
{
Debug.Console(1, destination, "Attempting to build source route from {0}", source.Key);
if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr))
routeDescr = null;
}
// otherwise, audioVideo needs to be handled as two steps.
else
{
Debug.Console(1, destination, "Attempting to build audio and video routes from {0}", source.Key);
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr);
if (!audioSuccess)
Debug.Console(1, destination, "Cannot find audio route to {0}", source.Key);
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr);
if (!videoSuccess)
Debug.Console(1, destination, "Cannot find video route to {0}", source.Key);
if (!audioSuccess && !videoSuccess)
routeDescr = null;
}
//Debug.Console(1, destination, "Route{0} discovered", routeDescr == null ? " NOT" : "");
return routeDescr;
}
/// <summary>
/// The recursive part of this. Will stop on each device, search its inputs for the
/// desired source and if not found, invoke this function for the each input port
/// hoping to find the source.
/// </summary>
/// <param name="destination"></param>
/// <param name="source"></param>
/// <param name="outputPortToUse">The RoutingOutputPort whose link is being checked for a route</param>
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
/// <param name="cycle">Just an informational counter</param>
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
/// <returns>true if source is hit</returns>
static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable)
{
cycle++;
Debug.Console(2, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key);
RoutingInputPort goodInputPort = null;
var destDevInputTies = TieLineCollection.Default.Where(t =>
t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video)));
// find a direct tie
var directTie = destDevInputTies.FirstOrDefault(
t => t.DestinationPort.ParentDevice == destination
&& t.SourcePort.ParentDevice == source);
if (directTie != null) // Found a tie directly to the source
{
goodInputPort = directTie.DestinationPort;
}
else // no direct-connect. Walk back devices.
{
Debug.Console(2, destination, "is not directly connected to {0}. Walking down tie lines", source.Key);
// No direct tie? Run back out on the inputs' attached devices...
// Only the ones that are routing devices
var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
if (alreadyCheckedDevices == null)
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
foreach (var inputTieToTry in attachedMidpoints)
{
var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key);
// Check if this previous device has already been walked
if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
{
Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key);
continue;
}
// haven't seen this device yet. Do it. Pass the output port to the next
// level to enable switching on success
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
alreadyCheckedDevices, signalType, cycle, routeTable);
if (upstreamRoutingSuccess)
{
Debug.Console(2, destination, "Upstream device route found");
goodInputPort = inputTieToTry.DestinationPort;
break; // Stop looping the inputs in this cycle
}
}
}
// we have a route on corresponding inputPort. *** Do the route ***
if (goodInputPort != null)
{
//Debug.Console(2, destination, "adding RouteDescriptor");
if (outputPortToUse == null)
{
// it's a sink device
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
}
else if (destination is IRouting)
{
routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort));
}
else // device is merely IRoutingInputOutputs
Debug.Console(2, destination, " No routing. Passthrough device");
//Debug.Console(2, destination, "Exiting cycle {0}", cycle);
return true;
}
Debug.Console(2, destination, "No route found to {0}", source.Key);
return false;
}
}
// MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE
/// <summary>
/// A collection of RouteDescriptors - typically the static DefaultCollection is used
/// </summary>
public class RouteDescriptorCollection
{
public static RouteDescriptorCollection DefaultCollection
{
get
{
if (_DefaultCollection == null)
_DefaultCollection = new RouteDescriptorCollection();
return _DefaultCollection;
}
}
static RouteDescriptorCollection _DefaultCollection;
List<RouteDescriptor> RouteDescriptors = new List<RouteDescriptor>();
/// <summary>
/// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
/// destination exists already, it will not be added - in order to preserve
/// proper route releasing.
/// </summary>
/// <param name="descriptor"></param>
public void AddRouteDescriptor(RouteDescriptor descriptor)
{
if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination))
{
Debug.Console(1, descriptor.Destination,
"Route to [{0}] already exists in global routes table", descriptor.Source.Key);
return;
}
RouteDescriptors.Add(descriptor);
}
/// <summary>
/// Gets the RouteDescriptor for a destination
/// </summary>
/// <returns>null if no RouteDescriptor for a destination exists</returns>
public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination)
{
return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
}
/// <summary>
/// Returns the RouteDescriptor for a given destination AND removes it from collection.
/// Returns null if no route with the provided destination exists.
/// </summary>
public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination)
{
var descr = GetRouteDescriptorForDestination(destination);
if (descr != null)
RouteDescriptors.Remove(descr);
return descr;
}
}
/// <summary>
/// Represents an collection of individual route steps between Source and Destination
/// </summary>
public class RouteDescriptor
{
public IRoutingInputs Destination { get; private set; }
public IRoutingOutputs Source { get; private set; }
public eRoutingSignalType SignalType { get; private set; }
public List<RouteSwitchDescriptor> Routes { get; private set; }
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType)
{
Destination = destination;
Source = source;
SignalType = signalType;
Routes = new List<RouteSwitchDescriptor>();
}
/// <summary>
/// Executes all routes described in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ExecuteRoutes()
{
foreach (var route in Routes)
{
Debug.Console(2, "ExecuteRoutes: {0}", route.ToString());
if (route.SwitchingDevice is IRoutingSink)
{
var device = route.SwitchingDevice as IRoutingSinkWithSwitching;
if (device == null)
continue;
device.ExecuteSwitch(route.InputPort.Selector);
}
else if (route.SwitchingDevice is IRouting)
{
(route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
Debug.Console(2, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
/// <summary>
/// Releases all routes in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ReleaseRoutes()
{
foreach (var route in Routes)
{
if (route.SwitchingDevice is IRouting)
{
// Pull the route from the port. Whatever is watching the output's in use tracker is
// responsible for responding appropriately.
route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
Debug.Console(2, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
public override string ToString()
{
var routesText = Routes.Select(r => r.ToString()).ToArray();
return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText));
}
}
/// <summary>
/// Represents an individual link for a route
/// </summary>
public class RouteSwitchDescriptor
{
public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } }
public RoutingOutputPort OutputPort { get; set; }
public RoutingInputPort InputPort { get; set; }
public RouteSwitchDescriptor(RoutingInputPort inputPort)
{
InputPort = inputPort;
}
public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort)
{
InputPort = inputPort;
OutputPort = outputPort;
}
public override string ToString()
{
if(SwitchingDevice is IRouting)
return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector);
else
return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DM;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public class RouteRequest
{
public IRoutingSink Destination {get; set;}
public IRoutingOutputs Source {get; set;}
public eRoutingSignalType SignalType {get; set;}
public void HandleCooldown(object sender, FeedbackEventArgs args)
{
var coolingDevice = sender as IWarmingCooling;
if(args.BoolValue == false)
{
Destination.ReleaseAndMakeRoute(Source, SignalType);
if(sender == null) return;
coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
}
}
}
/// <summary>
/// Extensions added to any IRoutingInputs classes to provide discovery-based routing
/// on those destinations.
/// </summary>
public static class IRoutingInputsExtensions
{
private static Dictionary<string, RouteRequest> RouteRequests = new Dictionary<string, RouteRequest>();
/// <summary>
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
/// in RouteDescriptorCollection.DefaultCollection
/// </summary>
public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
{
var routeRequest = new RouteRequest {
Destination = destination,
Source = source,
SignalType = signalType
};
var coolingDevice = destination as IWarmingCooling;
RouteRequest existingRouteRequest;
//We already have a route request for this device, and it's a cooling device and is cooling
if (RouteRequests.TryGetValue(destination.Key, out existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests[destination.Key] = routeRequest;
Debug.Console(2, "******************************************************** Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", destination.Key, routeRequest.Source.Key);
return;
}
//New Request
if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests.Add(destination.Key, routeRequest);
Debug.Console(2, "******************************************************** Device: {0} is cooling down. Storing route request to route to source key: {1}", destination.Key, routeRequest.Source.Key);
return;
}
if (RouteRequests.ContainsKey(destination.Key) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
{
RouteRequests.Remove(destination.Key);
Debug.Console(2, "******************************************************** Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", destination.Key, routeRequest.Source.Key);
}
destination.ReleaseRoute();
RunRouteRequest(routeRequest);
}
public static void RunRouteRequest(RouteRequest request)
{
if (request.Source == null) return;
var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType);
if (newRoute == null) return;
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
Debug.Console(2, request.Destination, "Executing full route");
newRoute.ExecuteRoutes();
}
/// <summary>
/// Will release the existing route on the destination, if it is found in
/// RouteDescriptorCollection.DefaultCollection
/// </summary>
/// <param name="destination"></param>
public static void ReleaseRoute(this IRoutingSink destination)
{
RouteRequest existingRequest;
if (RouteRequests.TryGetValue(destination.Key, out existingRequest) && destination is IWarmingCooling)
{
var coolingDevice = destination as IWarmingCooling;
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown;
}
RouteRequests.Remove(destination.Key);
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
if (current != null)
{
Debug.Console(1, destination, "Releasing current route: {0}", current.Source.Key);
current.ReleaseRoutes();
}
}
/// <summary>
/// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
/// Routes of type AudioVideo will be built as two separate routes, audio and video. If
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
/// of an audio/video route are discovered a route descriptor is returned. If no route is
/// discovered, then null is returned
/// </summary>
public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
{
var routeDescr = new RouteDescriptor(source, destination, signalType);
// if it's a single signal type, find the route
if ((signalType & (eRoutingSignalType.Audio & eRoutingSignalType.Video)) == (eRoutingSignalType.Audio & eRoutingSignalType.Video))
{
Debug.Console(1, destination, "Attempting to build source route from {0}", source.Key);
if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescr))
routeDescr = null;
}
// otherwise, audioVideo needs to be handled as two steps.
else
{
Debug.Console(1, destination, "Attempting to build audio and video routes from {0}", source.Key);
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescr);
if (!audioSuccess)
Debug.Console(1, destination, "Cannot find audio route to {0}", source.Key);
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescr);
if (!videoSuccess)
Debug.Console(1, destination, "Cannot find video route to {0}", source.Key);
if (!audioSuccess && !videoSuccess)
routeDescr = null;
}
//Debug.Console(1, destination, "Route{0} discovered", routeDescr == null ? " NOT" : "");
return routeDescr;
}
/// <summary>
/// The recursive part of this. Will stop on each device, search its inputs for the
/// desired source and if not found, invoke this function for the each input port
/// hoping to find the source.
/// </summary>
/// <param name="destination"></param>
/// <param name="source"></param>
/// <param name="outputPortToUse">The RoutingOutputPort whose link is being checked for a route</param>
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
/// <param name="cycle">Just an informational counter</param>
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
/// <returns>true if source is hit</returns>
static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable)
{
cycle++;
Debug.Console(2, "GetRouteToSource: {0} {1}--> {2}", cycle, source.Key, destination.Key);
RoutingInputPort goodInputPort = null;
var destDevInputTies = TieLineCollection.Default.Where(t =>
t.DestinationPort.ParentDevice == destination && (t.Type == signalType || (t.Type & (eRoutingSignalType.Audio | eRoutingSignalType.Video)) == (eRoutingSignalType.Audio | eRoutingSignalType.Video)));
// find a direct tie
var directTie = destDevInputTies.FirstOrDefault(
t => t.DestinationPort.ParentDevice == destination
&& t.SourcePort.ParentDevice == source);
if (directTie != null) // Found a tie directly to the source
{
goodInputPort = directTie.DestinationPort;
}
else // no direct-connect. Walk back devices.
{
Debug.Console(2, destination, "is not directly connected to {0}. Walking down tie lines", source.Key);
// No direct tie? Run back out on the inputs' attached devices...
// Only the ones that are routing devices
var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
if (alreadyCheckedDevices == null)
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
foreach (var inputTieToTry in attachedMidpoints)
{
var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
Debug.Console(2, destination, "Trying to find route on {0}", upstreamRoutingDevice.Key);
// Check if this previous device has already been walked
if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
{
Debug.Console(2, destination, "Skipping input {0} on {1}, this was already checked", upstreamRoutingDevice.Key, destination.Key);
continue;
}
// haven't seen this device yet. Do it. Pass the output port to the next
// level to enable switching on success
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
alreadyCheckedDevices, signalType, cycle, routeTable);
if (upstreamRoutingSuccess)
{
Debug.Console(2, destination, "Upstream device route found");
goodInputPort = inputTieToTry.DestinationPort;
break; // Stop looping the inputs in this cycle
}
}
}
// we have a route on corresponding inputPort. *** Do the route ***
if (goodInputPort != null)
{
//Debug.Console(2, destination, "adding RouteDescriptor");
if (outputPortToUse == null)
{
// it's a sink device
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
}
else if (destination is IRouting)
{
routeTable.Routes.Add(new RouteSwitchDescriptor (outputPortToUse, goodInputPort));
}
else // device is merely IRoutingInputOutputs
Debug.Console(2, destination, " No routing. Passthrough device");
//Debug.Console(2, destination, "Exiting cycle {0}", cycle);
return true;
}
Debug.Console(2, destination, "No route found to {0}", source.Key);
return false;
}
}
// MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE
/// <summary>
/// A collection of RouteDescriptors - typically the static DefaultCollection is used
/// </summary>
public class RouteDescriptorCollection
{
public static RouteDescriptorCollection DefaultCollection
{
get
{
if (_DefaultCollection == null)
_DefaultCollection = new RouteDescriptorCollection();
return _DefaultCollection;
}
}
static RouteDescriptorCollection _DefaultCollection;
List<RouteDescriptor> RouteDescriptors = new List<RouteDescriptor>();
/// <summary>
/// Adds a RouteDescriptor to the list. If an existing RouteDescriptor for the
/// destination exists already, it will not be added - in order to preserve
/// proper route releasing.
/// </summary>
/// <param name="descriptor"></param>
public void AddRouteDescriptor(RouteDescriptor descriptor)
{
if (RouteDescriptors.Any(t => t.Destination == descriptor.Destination))
{
Debug.Console(1, descriptor.Destination,
"Route to [{0}] already exists in global routes table", descriptor.Source.Key);
return;
}
RouteDescriptors.Add(descriptor);
}
/// <summary>
/// Gets the RouteDescriptor for a destination
/// </summary>
/// <returns>null if no RouteDescriptor for a destination exists</returns>
public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination)
{
return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination);
}
/// <summary>
/// Returns the RouteDescriptor for a given destination AND removes it from collection.
/// Returns null if no route with the provided destination exists.
/// </summary>
public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination)
{
var descr = GetRouteDescriptorForDestination(destination);
if (descr != null)
RouteDescriptors.Remove(descr);
return descr;
}
}
/// <summary>
/// Represents an collection of individual route steps between Source and Destination
/// </summary>
public class RouteDescriptor
{
public IRoutingInputs Destination { get; private set; }
public IRoutingOutputs Source { get; private set; }
public eRoutingSignalType SignalType { get; private set; }
public List<RouteSwitchDescriptor> Routes { get; private set; }
public RouteDescriptor(IRoutingOutputs source, IRoutingInputs destination, eRoutingSignalType signalType)
{
Destination = destination;
Source = source;
SignalType = signalType;
Routes = new List<RouteSwitchDescriptor>();
}
/// <summary>
/// Executes all routes described in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ExecuteRoutes()
{
foreach (var route in Routes)
{
Debug.Console(2, "ExecuteRoutes: {0}", route.ToString());
if (route.SwitchingDevice is IRoutingSink)
{
var device = route.SwitchingDevice as IRoutingSinkWithSwitching;
if (device == null)
continue;
device.ExecuteSwitch(route.InputPort.Selector);
}
else if (route.SwitchingDevice is IRouting)
{
(route.SwitchingDevice as IRouting).ExecuteSwitch(route.InputPort.Selector, route.OutputPort.Selector, SignalType);
route.OutputPort.InUseTracker.AddUser(Destination, "destination-" + SignalType);
Debug.Console(2, "Output port {0} routing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
/// <summary>
/// Releases all routes in this collection. Typically called via
/// extension method IRoutingInputs.ReleaseAndMakeRoute()
/// </summary>
public void ReleaseRoutes()
{
foreach (var route in Routes)
{
if (route.SwitchingDevice is IRouting)
{
// Pull the route from the port. Whatever is watching the output's in use tracker is
// responsible for responding appropriately.
route.OutputPort.InUseTracker.RemoveUser(Destination, "destination-" + SignalType);
Debug.Console(2, "Port {0} releasing. Count={1}", route.OutputPort.Key, route.OutputPort.InUseTracker.InUseCountFeedback.UShortValue);
}
}
}
public override string ToString()
{
var routesText = Routes.Select(r => r.ToString()).ToArray();
return string.Format("Route table from {0} to {1}:\r{2}", Source.Key, Destination.Key, string.Join("\r", routesText));
}
}
/// <summary>
/// Represents an individual link for a route
/// </summary>
public class RouteSwitchDescriptor
{
public IRoutingInputs SwitchingDevice { get { return InputPort.ParentDevice; } }
public RoutingOutputPort OutputPort { get; set; }
public RoutingInputPort InputPort { get; set; }
public RouteSwitchDescriptor(RoutingInputPort inputPort)
{
InputPort = inputPort;
}
public RouteSwitchDescriptor(RoutingOutputPort outputPort, RoutingInputPort inputPort)
{
InputPort = inputPort;
OutputPort = outputPort;
}
public override string ToString()
{
if(SwitchingDevice is IRouting)
return string.Format("{0} switches output '{1}' to input '{2}'", SwitchingDevice.Key, OutputPort.Selector, InputPort.Selector);
else
return string.Format("{0} switches to input '{1}'", SwitchingDevice.Key, InputPort.Selector);
}
}
}

View File

@@ -204,4 +204,9 @@ namespace PepperDash.Essentials.Core
SigType = sigType;
}
}
public interface IRoutingHasVideoInputSyncFeedbacks
{
FeedbackCollection<BoolFeedback> VideoInputSyncFeedbacks { get; }
}
}

View File

@@ -42,7 +42,7 @@ namespace PepperDash.Essentials.Core
public enum eRoutingPortConnectionType
{
None, BackplaneOnly, DisplayPort, Dvi, Hdmi, Rgb, Vga, LineAudio, DigitalAudio, Sdi,
Composite, Component, DmCat, DmMmFiber, DmSmFiber, Speaker, Streaming
Composite, Component, DmCat, DmMmFiber, DmSmFiber, Speaker, Streaming, UsbC, HdBaseT
}
/// <summary>

View File

@@ -199,5 +199,45 @@ namespace PepperDash.Essentials.Core.Routing
/// MediaPlayer
/// </summary>
public const string MediaPlayer = "mediaPlayer";
}
/// <summary>
/// UsbCIn
/// </summary>
public const string UsbCIn = "usbCIn";
/// <summary>
/// UsbCIn1
/// </summary>
public const string UsbCIn1 = "usbCIn1";
/// <summary>
/// UsbCIn2
/// </summary>
public const string UsbCIn2 = "usbCIn2";
/// <summary>
/// UsbCIn3
/// </summary>
public const string UsbCIn3 = "usbCIn3";
/// <summary>
/// UsbCOut
/// </summary>
public const string UsbCOut = "usbCOut";
/// <summary>
/// UsbCOut1
/// </summary>
public const string UsbCOut1 = "usbCOut1";
/// <summary>
/// UsbCOut2
/// </summary>
public const string UsbCOut2 = "usbCOut2";
/// <summary>
/// UsbCOut3
/// </summary>
public const string UsbCOut3 = "usbCOut3";
/// <summary>
/// HdBaseTIn
/// </summary>
public const string HdBaseTIn = "hdBaseTIn";
/// <summary>
/// HdBaseTOut
/// </summary>
public const string HdBaseTOut = "hdBaseTOut";
}
}

View File

@@ -0,0 +1,102 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public class CrestronGlobalSecretsProvider : ISecretProvider
{
public string Key { get; set; }
//Added for reference
public string Description { get; private set; }
public CrestronGlobalSecretsProvider(string key)
{
Key = key;
Description = String.Format("Default secret provider serving all local applications");
}
static CrestronGlobalSecretsProvider()
{
//Added for future encrypted reference
var secureSupported = CrestronSecureStorage.Supported;
CrestronDataStoreStatic.InitCrestronDataStore();
if (secureSupported)
{
//doThingsFuture
}
}
/// <summary>
/// Set secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <param name="value">Secret Value</param>
public bool SetSecret(string key, object value)
{
var secret = value as string;
CrestronDataStore.CDS_ERROR returnCode;
if (String.IsNullOrEmpty(secret))
{
returnCode = CrestronDataStoreStatic.clearGlobal(key);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully removed secret \"{0}\"", secret);
return true;
}
}
else
{
returnCode = CrestronDataStoreStatic.SetGlobalStringValue(key, secret);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully set secret \"{0}\"", secret);
return true;
}
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString());
return false;
}
/// <summary>
/// Retrieve secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>ISecret Object containing key, provider, and value</returns>
public ISecret GetSecret(string key)
{
string mySecret;
var getErrorCode = CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret);
switch (getErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(2, this, "Secret Successfully retrieved for {0}:{1}", Key, key);
return new CrestronSecret(key, mySecret, this);
default:
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to retrieve secret for {0}:{1} - {2}",
Key, key, getErrorCode.ToString());
return null;
}
}
/// <summary>
/// Determine if a secret is present within the provider without retrieving it
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>bool if present</returns>
public bool TestSecret(string key)
{
string mySecret;
return CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS;
}
}
}

View File

@@ -1,97 +1,103 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public class CrestronSecretsProvider : ISecretProvider
{
public string Key { get; set; }
//Added for reference
private static readonly bool SecureSupported;
public CrestronSecretsProvider(string key)
{
Key = key;
}
static CrestronSecretsProvider()
{
//Added for future encrypted reference
SecureSupported = CrestronSecureStorage.Supported;
CrestronDataStoreStatic.InitCrestronDataStore();
if (SecureSupported)
{
//doThingsFuture
}
}
/// <summary>
/// Set secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <param name="value">Secret Value</param>
public bool SetSecret(string key, object value)
{
var secret = value as string;
if (String.IsNullOrEmpty(secret))
{
Debug.Console(2, this, "Unable to set secret for {0}:{1} - value is empty.", Key, key);
return false;
}
var setErrorCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret);
switch (setErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(1, this,"Secret Successfully Set for {0}:{1}", Key, key);
return true;
default:
Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, setErrorCode.ToString());
return false;
}
}
/// <summary>
/// Retrieve secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>ISecret Object containing key, provider, and value</returns>
public ISecret GetSecret(string key)
{
string mySecret;
var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret);
switch (getErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(2, this, "Secret Successfully retrieved for {0}:{1}", Key, key);
return new CrestronSecret(key, mySecret, this);
default:
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to retrieve secret for {0}:{1} - {2}",
Key, key, getErrorCode.ToString());
return null;
}
}
}
/// <summary>
/// Special container class for CrestronSecret provider
/// </summary>
public class CrestronSecret : ISecret
{
public ISecretProvider Provider { get; private set; }
public string Key { get; private set; }
public object Value { get; private set; }
public CrestronSecret(string key, string value, ISecretProvider provider)
{
Key = key;
Value = value;
Provider = provider;
}
}
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore;
using PepperDash.Core;
using Crestron.SimplSharpPro;
namespace PepperDash.Essentials.Core
{
public class CrestronLocalSecretsProvider : ISecretProvider
{
public string Key { get; set; }
//Added for reference
public string Description { get; private set; }
public CrestronLocalSecretsProvider(string key)
{
Key = key;
Description = String.Format("Default secret provider serving Essentials Application {0}", InitialParametersClass.ApplicationNumber);
}
static CrestronLocalSecretsProvider()
{
//Added for future encrypted reference
var secureSupported = CrestronSecureStorage.Supported;
CrestronDataStoreStatic.InitCrestronDataStore();
if (secureSupported)
{
//doThingsFuture
}
}
/// <summary>
/// Set secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <param name="value">Secret Value</param>
public bool SetSecret(string key, object value)
{
var secret = value as string;
CrestronDataStore.CDS_ERROR returnCode;
if (String.IsNullOrEmpty(secret))
{
returnCode = CrestronDataStoreStatic.clearLocal(key);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully removed secret \"{0}\"", secret);
return true;
}
}
else
{
returnCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully set secret \"{0}\"", secret);
return true;
}
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString());
return false;
}
/// <summary>
/// Retrieve secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>ISecret Object containing key, provider, and value</returns>
public ISecret GetSecret(string key)
{
string mySecret;
var getErrorCode = CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret);
switch (getErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(2, this, "Secret Successfully retrieved for {0}:{1}", Key, key);
return new CrestronSecret(key, mySecret, this);
default:
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to retrieve secret for {0}:{1} - {2}",
Key, key, getErrorCode.ToString());
return null;
}
}
/// <summary>
/// Determine if a secret is present within the provider without retrieving it
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>bool if present</returns>
public bool TestSecret(string key)
{
string mySecret;
return CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Special container class for CrestronSecret provider
/// </summary>
public class CrestronSecret : ISecret
{
public ISecretProvider Provider { get; private set; }
public string Key { get; private set; }
public object Value { get; private set; }
public CrestronSecret(string key, string value, ISecretProvider provider)
{
Key = key;
Value = value;
Provider = provider;
}
}
}

View File

@@ -7,9 +7,32 @@ namespace PepperDash.Essentials.Core
/// </summary>
public interface ISecretProvider : IKeyed
{
/// <summary>
/// Set secret value for provider by key
/// </summary>
/// <param name="key">key of secret to set</param>
/// <param name="value">value to set secret to</param>
/// <returns></returns>
bool SetSecret(string key, object value);
/// <summary>
/// Return object containing secret from provider
/// </summary>
/// <param name="key">key of secret to retrieve</param>
/// <returns></returns>
ISecret GetSecret(string key);
/// <summary>
/// Verifies presence of secret
/// </summary>
/// <param name="key">key of secret to chek</param>
/// <returns></returns>
bool TestSecret(string key);
/// <summary>
/// Description of the secrets provider
/// </summary>
string Description { get; }
}
/// <summary>
@@ -17,8 +40,19 @@ namespace PepperDash.Essentials.Core
/// </summary>
public interface ISecret
{
/// <summary>
/// Instance of ISecretProvider that the secret belongs to
/// </summary>
ISecretProvider Provider { get; }
/// <summary>
/// Key of the secret in the provider
/// </summary>
string Key { get; }
/// <summary>
/// Value of the secret
/// </summary>
object Value { get; }
}
}

View File

@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public static class SecretsManager
@@ -16,18 +16,28 @@ namespace PepperDash.Essentials.Core
public static void Initialize()
{
AddSecretProvider("default", new CrestronSecretsProvider("default"));
AddSecretProvider("default", new CrestronLocalSecretsProvider("default"));
AddSecretProvider("CrestronGlobalSecrets", new CrestronGlobalSecretsProvider("CrestronGlobalSecrets"));
CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret",
"Adds secrets to secret provider",
"Adds secret to secrets provider",
ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret",
"Updates secrets in secret provider",
"Updates secret in secrets provider",
ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret",
"Deletes secrets in secret provider",
"Deletes secret from secrest provider",
ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(ListProviders, "secretproviderlist",
"Return list of all valid secrets providers",
ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(GetProviderInfo, "secretproviderinfo",
"Return data about secrets provider",
ConsoleAccessLevelEnum.AccessAdministrator);
}
@@ -54,6 +64,79 @@ namespace PepperDash.Essentials.Core
return secret;
}
public static void GetProviderInfo(string cmd)
{
string response;
var args = cmd.Split(' ');
if (cmd.Length == 0 || (args.Length == 1 && args[0] == "?"))
{
response = "Returns data about secrets provider. Format 'secretproviderinfo <provider>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1)
{
var provider = GetSecretProviderByKey(args[0]);
if (provider == null)
{
response = "Invalid secrets provider key";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response = String.Format("{0} : {1}", provider.Key, provider.Description);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
}
/// <summary>
/// Console Command that returns all valid secrets in the essentials program.
/// </summary>
/// <param name="cmd"></param>
public static void ListProviders(string cmd)
{
var response = String.Empty;
var args = cmd.Split(' ');
if (cmd.Length == 0)
{
if (Secrets != null && Secrets.Count > 0)
{
response = Secrets.Aggregate(response,
(current, secretProvider) => current + (secretProvider.Key + "\n\r"));
}
else
{
response = "No Secrets Providers Available";
}
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Reports all valid and preset Secret providers";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
}
/// <summary>
/// Add secret provider to secrets dictionary
/// </summary>
@@ -65,6 +148,7 @@ namespace PepperDash.Essentials.Core
{
Secrets.Add(key, provider);
Debug.Console(1, "Secrets provider '{0}' added to SecretsManager", key);
return;
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key );
}
@@ -81,13 +165,13 @@ namespace PepperDash.Essentials.Core
{
Secrets.Add(key, provider);
Debug.Console(1, "Secrets provider '{0}' added to SecretsManager", key);
return;
}
if (overwrite)
{
Secrets.Add(key, provider);
Debug.Console(1, Debug.ErrorLogLevel.Notice, "Provider with the key '{0}' already exists in secrets. Overwriting with new secrets provider.", key);
return;
}
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Unable to add Provider '{0}' to Secrets. Provider with that key already exists", key);
}
@@ -100,14 +184,14 @@ namespace PepperDash.Essentials.Core
if (args.Length == 0)
{
//some Instructional Text
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>";
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>";
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
@@ -134,23 +218,7 @@ namespace PepperDash.Essentials.Core
var key = args[1];
var secret = args[2];
if (provider.GetSecret(key) == null)
{
response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response =
String.Format(
"Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it");
CrestronConsole.ConsoleCommandResponse(response);
CrestronConsole.ConsoleCommandResponse(SetSecret(provider, key, secret));
}
private static void UpdateSecretProcess(string cmd)
@@ -161,7 +229,7 @@ namespace PepperDash.Essentials.Core
if (args.Length == 0)
{
//some Instructional Text
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>";
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
@@ -169,7 +237,7 @@ namespace PepperDash.Essentials.Core
if (args.Length == 1 && args[0] == "?")
{
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>";
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
@@ -198,23 +266,49 @@ namespace PepperDash.Essentials.Core
var key = args[1];
var secret = args[2];
if (provider.GetSecret(key) != null)
{
response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
CrestronConsole.ConsoleCommandResponse(UpdateSecret(provider, key, secret));
}
private static string UpdateSecret(ISecretProvider provider, string key, string secret)
{
var secretPresent = provider.TestSecret(key);
Debug.Console(2, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key);
if (!secretPresent)
return
String.Format(
"Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to modify it");
var response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
return response;
}
private static string SetSecret(ISecretProvider provider, string key, string secret)
{
var secretPresent = provider.TestSecret(key);
Debug.Console(2, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key);
if (secretPresent)
return
String.Format(
"Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it");
var response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
return response;
response =
String.Format(
"Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to create a new secret");
CrestronConsole.ConsoleCommandResponse(response);
}
private static void DeleteSecretProcess(string cmd)
@@ -225,14 +319,14 @@ namespace PepperDash.Essentials.Core
if (args.Length == 0)
{
//some Instructional Text
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>";
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>";
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}

View File

@@ -19,6 +19,7 @@ namespace PepperDash.Essentials.Core.Shades
/// <summary>
/// Requirements for a device that implements basic Open/Close shade control
/// </summary>
[Obsolete("Please use IShadesOpenCloseStop instead")]
public interface IShadesOpenClose
{
void Open();
@@ -28,15 +29,26 @@ namespace PepperDash.Essentials.Core.Shades
/// <summary>
/// Requirements for a device that implements basic Open/Close/Stop shade control (Uses 3 relays)
/// </summary>
public interface IShadesOpenCloseStop : IShadesOpenClose
{
void StopOrPreset();
string StopOrPresetButtonLabel { get; }
public interface IShadesOpenCloseStop
{
void Open();
void Close();
void Stop();
}
public interface IShadesOpenClosePreset : IShadesOpenCloseStop
{
void RecallPreset(uint presetNumber);
void SavePreset(uint presetNumber);
string StopOrPresetButtonLabel { get; }
event EventHandler PresetSaved;
}
/// <summary>
/// Requirements for a shade that implements press/hold raise/lower functions
/// </summary>
/// </summary>
[Obsolete("Please use IShadesOpenCloseStop instead")]
public interface IShadesRaiseLower
{
void Raise(bool state);
@@ -55,7 +67,7 @@ namespace PepperDash.Essentials.Core.Shades
/// <summary>
/// Requirements for a shade/scene that is open or closed
/// </summary>
public interface IShadesOpenClosedFeedback: IShadesOpenClose
public interface IShadesOpenClosedFeedback: IShadesOpenCloseStop
{
BoolFeedback ShadeIsOpenFeedback { get; }
BoolFeedback ShadeIsClosedFeedback { get; }
@@ -63,15 +75,16 @@ namespace PepperDash.Essentials.Core.Shades
/// <summary>
///
/// </summary>
public interface IShadesStop
/// </summary>
[Obsolete("Please use IShadesOpenCloseStop instead")]
public interface IShadesStop
{
void Stop();
}
/// <summary>
///
/// </summary>
/// Used to implement raise/stop/lower/stop from single button
/// </summary>
public interface IShadesStopOrMove
{
void OpenOrStop();
@@ -82,7 +95,7 @@ namespace PepperDash.Essentials.Core.Shades
/// <summary>
/// Basic feedback for shades/scene stopped
/// </summary>
public interface IShadesStopFeedback
public interface IShadesStopFeedback : IShadesOpenCloseStop
{
BoolFeedback IsStoppedFeedback { get; }
}

View File

@@ -12,7 +12,7 @@ namespace PepperDash.Essentials.Core.Shades
/// <summary>
/// Base class for a shade device
/// </summary>
public abstract class ShadeBase : EssentialsDevice, IShadesOpenClose
public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop
{
public ShadeBase(string key, string name)
: base(key, name)
@@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Core.Shades
#region iShadesOpenClose Members
public abstract void Open();
public abstract void StopOrPreset();
public abstract void Stop();
public abstract void Close();
#endregion

View File

@@ -144,7 +144,7 @@ namespace PepperDash.Essentials.Core
public UShortOutputSig GetUShortOutputSig(uint index, uint sigNum)
{
if (sigNum > UShortIncrement) return null;
return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetBoolFeedbackSigName(index, sigNum)));
return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum)));
}
/// <summary>
@@ -159,7 +159,7 @@ namespace PepperDash.Essentials.Core
public StringOutputSig GetStringOutputSig(uint index, uint sigNum)
{
if (sigNum > StringIncrement) return null;
return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetBoolFeedbackSigName(index, sigNum)));
return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum)));
}
/// <summary>

View File

@@ -1,144 +1,371 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using System.Globalization;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Touchpanels
{
/// <summary>
/// A wrapper class for the touchpanel portion of an MPC3 class process to allow for configurable
/// behavior of the keybad buttons
/// </summary>
public class Mpc3TouchpanelController : Device
{
MPC3Basic _Touchpanel;
/// <summary>
/// A wrapper class for the touchpanel portion of an MPC3 class process to allow for configurable
/// behavior of the keybad buttons
/// </summary>
public class Mpc3TouchpanelController : Device
{
readonly MPC3Basic _touchpanel;
Dictionary<string, KeypadButton> _Buttons;
readonly Dictionary<string, KeypadButton> _buttons;
public Mpc3TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary<string, KeypadButton> buttons)
: base(key, name)
{
_Touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic;
_Buttons = buttons;
public Mpc3TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary<string, KeypadButton> buttons)
: base(key, name)
{
_touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic;
if (_touchpanel == null)
{
Debug.Console(1, this, "Failed to construct MPC3 Touchpanel Controller with key {0}, check configuration", key);
return;
}
_Touchpanel.ButtonStateChange += new Crestron.SimplSharpPro.DeviceSupport.ButtonEventHandler(_Touchpanel_ButtonStateChange);
if (_touchpanel.Registerable)
{
var registrationResponse = _touchpanel.Register();
Debug.Console(0, this, "touchpanel registration response: {0}", registrationResponse);
}
AddPostActivationAction(() =>
{
// Link up the button feedbacks to the specified BoolFeedbacks
foreach (var button in _Buttons)
{
var feedbackConfig = button.Value.Feedback;
var device = DeviceManager.GetDeviceForKey(feedbackConfig.DeviceKey) as Device;
if (device != null)
{
var bKey = button.Key.ToLower();
_touchpanel.BaseEvent += _touchpanel_BaseEvent;
_touchpanel.ButtonStateChange += _touchpanel_ButtonStateChange;
_touchpanel.PanelStateChange += _touchpanel_PanelStateChange;
var feedback = device.GetFeedbackProperty(feedbackConfig.FeedbackName);
_buttons = buttons;
if (_buttons == null)
{
Debug.Console(1, this,
"Button properties are null, failed to setup MPC3 Touch Controller, check configuration");
return;
}
var bFeedback = feedback as BoolFeedback;
var iFeedback = feedback as IntFeedback;
if (bFeedback != null)
{
AddPostActivationAction(() =>
{
foreach (var button in _buttons)
{
var buttonKey = button.Key.ToLower();
var buttonConfig = button.Value;
if (bKey == "power")
{
bFeedback.LinkCrestronFeedback(_Touchpanel.FeedbackPower);
continue;
}
else if (bKey == "mute")
{
bFeedback.LinkCrestronFeedback(_Touchpanel.FeedbackMute);
continue;
}
InitializeButton(buttonKey, buttonConfig);
InitializeButtonFeedback(buttonKey, buttonConfig);
}
// Link to the Crestron Feedback corresponding to the button number
bFeedback.LinkCrestronFeedback(_Touchpanel.Feedbacks[UInt16.Parse(button.Key)]);
}
else if (iFeedback != null)
{
if (bKey == "volumefeedback")
{
var volFeedback = feedback as IntFeedback;
// TODO: Figure out how to subsribe to a volume IntFeedback and link it to the voluem
volFeedback.LinkInputSig(_Touchpanel.VolumeBargraph);
}
}
else
{
Debug.Console(1, this, "Unable to get BoolFeedback with name: {0} from device: {1}", feedbackConfig.FeedbackName, device.Key);
}
}
else
{
Debug.Console(1, this, "Unable to get device with key: {0}", feedbackConfig.DeviceKey);
}
}
});
}
ListButtons();
});
}
void _Touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args)
{
Debug.Console(1, this, "Button {0} ({1}), {2}", args.Button.Number, args.Button.Name, args.NewButtonState);
var type = args.NewButtonState.ToString();
/// <summary>
/// Enables/disables buttons based on event type configuration
/// </summary>
/// <param name="key"></param>
/// <param name="config"></param>
public void InitializeButton(string key, KeypadButton config)
{
if (config == null)
{
Debug.Console(1, this, "Button '{0}' config is null, unable to initialize", key);
return;
}
if (_Buttons.ContainsKey(args.Button.Number.ToString()))
{
Press(args.Button.Number.ToString(), type);
}
else if(_Buttons.ContainsKey(args.Button.Name.ToString()))
{
Press(args.Button.Name.ToString(), type);
}
}
int buttonNumber;
TryParseInt(key, out buttonNumber);
/// <summary>
/// Runs the function associated with this button/type. One of the following strings:
/// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased
/// </summary>
/// <param name="number"></param>
/// <param name="type"></param>
public void Press(string number, string type)
{
// TODO: In future, consider modifying this to generate actions at device activation time
// to prevent the need to dynamically call the method via reflection on each button press
if (!_Buttons.ContainsKey(number)) { return; }
var but = _Buttons[number];
if (but.EventTypes.ContainsKey(type))
{
foreach (var a in but.EventTypes[type]) { DeviceJsonApi.DoDeviceAction(a); }
}
}
var buttonEventTypes = config.EventTypes;
BoolOutputSig enabledFb = null;
BoolOutputSig disabledFb = null;
switch (key)
{
case ("power"):
{
if (buttonEventTypes == null || buttonEventTypes.Keys == null)
_touchpanel.DisablePowerButton();
else
_touchpanel.EnablePowerButton();
}
enabledFb = _touchpanel.PowerButtonEnabledFeedBack;
disabledFb = _touchpanel.PowerButtonDisabledFeedBack;
/// <summary>
/// Represents the configuration of a keybad buggon
/// </summary>
public class KeypadButton
{
public Dictionary<string, DeviceActionWrapper[]> EventTypes { get; set; }
public KeypadButtonFeedback Feedback { get; set; }
break;
}
//case ("volumeup"):
// {
// break;
// }
//case ("volumedown"):
// {
// break;
// }
//case ("volumefeedback"):
// {
// break;
// }
case ("mute"):
{
if (buttonEventTypes == null || buttonEventTypes.Keys == null)
_touchpanel.DisableMuteButton();
else
_touchpanel.EnableMuteButton();
public KeypadButton()
{
EventTypes = new Dictionary<string, DeviceActionWrapper[]>();
Feedback = new KeypadButtonFeedback();
}
}
/// <summary>
///
/// </summary>
public class KeypadButtonFeedback
{
public string DeviceKey { get; set; }
public string FeedbackName { get; set; }
}
enabledFb = _touchpanel.MuteButtonEnabledFeedBack;
disabledFb = _touchpanel.MuteButtonDisabledFeedBack;
break;
}
default:
{
if (buttonNumber == 0 || buttonNumber > 9)
break;
if (buttonEventTypes == null || buttonEventTypes.Keys == null)
_touchpanel.DisableNumericalButton((uint)buttonNumber);
else
_touchpanel.EnableNumericalButton((uint)buttonNumber);
if (_touchpanel.NumericalButtonEnabledFeedBack != null)
enabledFb = _touchpanel.NumericalButtonEnabledFeedBack[(uint)buttonNumber];
if (_touchpanel.NumericalButtonDisabledFeedBack != null)
disabledFb = _touchpanel.NumericalButtonDisabledFeedBack[(uint)buttonNumber];
break;
}
}
Debug.Console(0, this, "InitializeButton: key-'{0}' enabledFb-'{1}', disabledFb-'{2}'",
key, enabledFb ?? (object)"null", disabledFb ?? (object)"null");
}
/// <summary>
/// Links button feedback if configured
/// </summary>
/// <param name="key"></param>
/// <param name="config"></param>
public void InitializeButtonFeedback(string key, KeypadButton config)
{
//Debug.Console(1, this, "Initializing button '{0}' feedback...", key);
if (config == null)
{
Debug.Console(1, this, "Button '{0}' config is null, skipping.", key);
return;
}
int buttonNumber;
TryParseInt(key, out buttonNumber);
// Link up the button feedbacks to the specified device feedback
var buttonFeedback = config.Feedback;
if (buttonFeedback == null || string.IsNullOrEmpty(buttonFeedback.DeviceKey))
{
Debug.Console(1, this, "Button '{0}' feedback not configured, skipping.",
key);
return;
}
Feedback deviceFeedback;
try
{
var device = DeviceManager.GetDeviceForKey(buttonFeedback.DeviceKey) as Device;
if (device == null)
{
Debug.Console(1, this, "Button '{0}' feedback deviceKey '{1}' not found.",
key, buttonFeedback.DeviceKey);
return;
}
deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName);
if (deviceFeedback == null)
{
Debug.Console(1, this, "Button '{0}' feedbackName property '{1}' not found.",
key, buttonFeedback.FeedbackName);
return;
}
// TODO [ ] verify if this can replace the current method
//Debug.Console(0, this, "deviceFeedback.GetType().Name: '{0}'", deviceFeedback.GetType().Name);
//switch (feedback.GetType().Name.ToLower())
//{
// case("boolfeedback"):
// {
// break;
// }
// case("intfeedback"):
// {
// break;
// }
// case("stringfeedback"):
// {
// break;
// }
//}
}
catch (Exception ex)
{
Debug.Console(1, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception Message: {0}",
ex.Message, key, buttonFeedback.DeviceKey);
Debug.Console(2, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception StackTrace: {0}",
ex.StackTrace, key, buttonFeedback.DeviceKey);
if (ex.InnerException != null) Debug.Console(2, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') InnerException: {0}",
ex.InnerException, key, buttonFeedback.DeviceKey);
return;
}
var boolFeedback = deviceFeedback as BoolFeedback;
var intFeedback = deviceFeedback as IntFeedback;
switch (key)
{
case ("power"):
{
if (boolFeedback != null) boolFeedback.LinkCrestronFeedback(_touchpanel.FeedbackPower);
break;
}
case ("volumeup"):
case ("volumedown"):
case ("volumefeedback"):
{
if (intFeedback != null)
{
var volumeFeedback = intFeedback;
volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph);
}
break;
}
case ("mute"):
{
if (boolFeedback != null) boolFeedback.LinkCrestronFeedback(_touchpanel.FeedbackMute);
break;
}
default:
{
if (boolFeedback != null) boolFeedback.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]);
break;
}
}
}
/// <summary>
/// Try parse int helper method
/// </summary>
/// <param name="str"></param>
/// <param name="result"></param>
/// <returns></returns>
public bool TryParseInt(string str, out int result)
{
try
{
result = int.Parse(str);
return true;
}
catch
{
result = 0;
return false;
}
}
private void _touchpanel_BaseEvent(GenericBase device, BaseEventArgs args)
{
Debug.Console(1, this, "BaseEvent: eventId-'{0}', index-'{1}'", args.EventId, args.Index);
}
private void _touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args)
{
Debug.Console(1, this, "ButtonStateChange: buttonNumber-'{0}' buttonName-'{1}', buttonState-'{2}'", args.Button.Number, args.Button.Name, args.NewButtonState);
var type = args.NewButtonState.ToString();
if (_buttons.ContainsKey(args.Button.Number.ToString(CultureInfo.InvariantCulture)))
{
Press(args.Button.Number.ToString(CultureInfo.InvariantCulture), type);
}
else if (_buttons.ContainsKey(args.Button.Name.ToString()))
{
Press(args.Button.Name.ToString(), type);
}
}
private void _touchpanel_PanelStateChange(GenericBase device, BaseEventArgs args)
{
Debug.Console(1, this, "PanelStateChange: eventId-'{0}', index-'{1}'", args.EventId, args.Index);
}
/// <summary>
/// Runs the function associated with this button/type. One of the following strings:
/// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased
/// </summary>
/// <param name="buttonKey"></param>
/// <param name="type"></param>
public void Press(string buttonKey, string type)
{
Debug.Console(2, this, "Press: buttonKey-'{0}', type-'{1}'", buttonKey, type);
// TODO: In future, consider modifying this to generate actions at device activation time
// to prevent the need to dynamically call the method via reflection on each button press
if (!_buttons.ContainsKey(buttonKey)) return;
var button = _buttons[buttonKey];
if (!button.EventTypes.ContainsKey(type)) return;
foreach (var eventType in button.EventTypes[type]) DeviceJsonApi.DoDeviceAction(eventType);
}
public void ListButtons()
{
var line = new string('-', 35);
Debug.Console(0, this, line);
Debug.Console(0, this, "MPC3 Controller {0} - Available Butons", Key);
foreach (var button in _buttons)
{
Debug.Console(0, this, "Key: {0}", button.Key);
}
Debug.Console(0, this, line);
}
}
/// <summary>
/// Represents the configuration of a keypad button
/// </summary>
public class KeypadButton
{
[JsonProperty("eventTypes")]
public Dictionary<string, DeviceActionWrapper[]> EventTypes { get; set; }
[JsonProperty("feedback")]
public KeypadButtonFeedback Feedback { get; set; }
public KeypadButton()
{
EventTypes = new Dictionary<string, DeviceActionWrapper[]>();
Feedback = new KeypadButtonFeedback();
}
}
/// <summary>
/// Represents the configuration of a keypad button feedback
/// </summary>
public class KeypadButtonFeedback
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("feedbackName")]
public string FeedbackName { get; set; }
}
}

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using Crestron.SimplSharpPro.UI;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
namespace PepperDash.Essentials.Core.UI
{
public abstract class TouchpanelBase: EssentialsDevice, IHasBasicTriListWithSmartObject
{
protected CrestronTouchpanelPropertiesConfig _config;
public BasicTriListWithSmartObject Panel { get; private set; }
/// <summary>
/// Constructor for use with device Factory. A touch panel device will be created based on the provided IP-ID and the
/// type of the panel. The SGD File path can be specified using the config property, or a default one located in the program directory if none
/// is provided.
/// </summary>
/// <param name="key">Essentials Device Key</param>
/// <param name="name">Essentials Device Name</param>
/// <param name="type">Touchpanel Type to build</param>
/// <param name="config">Touchpanel Configuration</param>
/// <param name="id">IP-ID to use for touch panel</param>
protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config)
:base(key, name)
{
if (panel == null)
{
Debug.Console(0, this, "Panel is not valid. Touchpanel class WILL NOT work correctly");
return;
}
Panel = panel;
Panel.SigChange += Panel_SigChange;
if (Panel is TswFt5ButtonSystem)
{
var tsw = Panel as TswFt5ButtonSystem;
tsw.ExtenderSystemReservedSigs.Use();
tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange
+= ExtenderSystemReservedSigs_DeviceExtenderSigChange;
tsw.ButtonStateChange += Tsw_ButtonStateChange;
}
_config = config;
AddPreActivationAction(() => {
if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success)
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason);
// Give up cleanly if SGD is not present.
var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile;
if (!File.Exists(sgdName))
{
Debug.Console(0, this, "Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName);
sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile;
if (!File.Exists(sgdName))
{
Debug.Console(0, this, "Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName);
return;
}
}
Panel.LoadSmartObjects(sgdName);
});
AddPostActivationAction(() =>
{
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner;
if (roomCombiner != null)
{
// Subscribe to the even
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(roomCombiner_RoomCombinationScenarioChanged);
// Connect to the initial roomKey
if (roomCombiner.CurrentScenario != null)
{
// Use the current scenario
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
}
else
{
// Current Scenario not yet set. Use default
SetupPanelDrivers(_config.DefaultRoomKey);
}
}
else
{
// No room combiner, use the default key
SetupPanelDrivers(_config.DefaultRoomKey);
}
});
}
/// <summary>
/// Setup Panel operation
/// </summary>
/// <param name="roomKey">Room Key for this panel</param>
protected abstract void SetupPanelDrivers(string roomKey);
/// <summary>
/// Event handler for System Extender Events
/// </summary>
/// <param name="currentDeviceExtender"></param>
/// <param name="args"></param>
protected abstract void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args);
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
{
var roomCombiner = sender as IEssentialsRoomCombiner;
DetermineRoomKeyFromScenario(roomCombiner.CurrentScenario);
}
/// <summary>
/// Determines the room key to use based on the scenario
/// </summary>
/// <param name="scenario"></param>
protected virtual void DetermineRoomKeyFromScenario(IRoomCombinationScenario scenario)
{
string newRoomKey = null;
if (scenario.UiMap.ContainsKey(Key))
{
newRoomKey = scenario.UiMap[Key];
}
else if (scenario.UiMap.ContainsKey(_config.DefaultRoomKey))
{
newRoomKey = scenario.UiMap[_config.DefaultRoomKey];
}
SetupPanelDrivers(newRoomKey);
}
private void Panel_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args)
{
if (Debug.Level == 2)
Debug.Console(2, this, "Sig 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);
}
private void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args)
{
var uo = args.Button.UserObject;
if(uo is Action<bool>)
(uo as Action<bool>)(args.Button.State == eButtonState.Pressed);
}
}
}

View File

@@ -0,0 +1,224 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.WebScripting;
using PepperDash.Core;
using PepperDash.Core.Web;
using PepperDash.Essentials.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web
{
public class EssemtialsWebApi : EssentialsDevice
{
private readonly WebApiServer _server;
///<example>
/// http(s)://{ipaddress}/cws/{basePath}
/// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath}
/// </example>
private readonly string _defaultBasePath = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
? string.Format("/app{0:00}/api", InitialParametersClass.ApplicationNumber)
: "/api";
private const int DebugTrace = 0;
private const int DebugInfo = 1;
private const int DebugVerbose = 2;
/// <summary>
/// CWS base path
/// </summary>
public string BasePath { get; private set; }
/// <summary>
/// Tracks if CWS is registered
/// </summary>
public bool IsRegistered
{
get { return _server.IsRegistered; }
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public EssemtialsWebApi(string key, string name)
: this(key, name, null)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
/// <param name="config"></param>
public EssemtialsWebApi(string key, string name, EssentialsWebApiPropertiesConfig config)
: base(key, name)
{
Key = key;
if (config == null)
BasePath = _defaultBasePath;
else
BasePath = string.IsNullOrEmpty(config.BasePath) ? _defaultBasePath : config.BasePath;
_server = new WebApiServer(Key, Name, BasePath);
}
/// <summary>
/// Custom activate, add routes
/// </summary>
/// <returns></returns>
public override bool CustomActivate()
{
var routes = new List<HttpCwsRoute>
{
new HttpCwsRoute("reportversions")
{
Name = "ReportVersions",
RouteHandler = new ReportVersionsRequestHandler()
},
new HttpCwsRoute("appdebug")
{
Name = "AppDebug",
RouteHandler = new AppDebugRequestHandler()
},
new HttpCwsRoute("devlist")
{
Name = "DevList",
RouteHandler = new DevListRequestHandler()
},
new HttpCwsRoute("devprops")
{
Name = "DevProps",
RouteHandler = new DevPropsRequestHandler()
},
new HttpCwsRoute("devjson")
{
Name = "DevJson",
RouteHandler = new DevJsonRequestHandler()
},
new HttpCwsRoute("setdevicestreamdebug")
{
Name = "SetDeviceStreamDebug",
RouteHandler = new SetDeviceStreamDebugRequestHandler()
},
new HttpCwsRoute("disableallstreamdebug")
{
Name = "DisableAllStreamDebug",
RouteHandler = new DisableAllStreamDebugRequestHandler()
},
new HttpCwsRoute("showconfig")
{
Name = "ShowConfig",
RouteHandler = new ShowConfigRequestHandler()
},
new HttpCwsRoute("gettypes")
{
Name = "GetTypes",
RouteHandler = new GetTypesRequestHandler()
},
new HttpCwsRoute("gettypes/{filter}")
{
Name = "GetTypesByFilter",
RouteHandler = new GetTypesByFilterRequestHandler()
},
new HttpCwsRoute("getjoinmap/{bridgeKey}")
{
Name = "GetJoinMapsForBridgeKey",
RouteHandler = new GetJoinMapForBridgeKeyRequestHandler()
},
new HttpCwsRoute("getjoinmap/{bridgeKey}/{deviceKey}")
{
Name = "GetJoinMapsForDeviceKey",
RouteHandler = new GetJoinMapForDeviceKeyRequestHandler()
},
new HttpCwsRoute("feedbacks/{deviceKey}")
{
Name = "GetFeedbacksForDeviceKey",
RouteHandler = new GetFeedbacksForDeviceRequestHandler()
}
};
foreach (var route in routes.Where(route => route != null))
{
var r = route;
_server.AddRoute(r);
}
return base.CustomActivate();
}
/// <summary>
/// Initializes the CWS class
/// </summary>
public override void Initialize()
{
// If running on an appliance
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
{
/*
WEBSERVER [ON | OFF | TIMEOUT <VALUE IN SECONDS> | MAXSESSIONSPERUSER <Number of sessions>]
*/
var response = string.Empty;
CrestronConsole.SendControlSystemCommand("webserver", ref response);
if (response.Contains("OFF")) return;
var is4Series = eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4);
Debug.Console(DebugTrace, Debug.ErrorLogLevel.Notice, "Starting Essentials Web API on {0} Appliance", is4Series ? "4-series" : "3-series");
_server.Start();
GetPaths();
return;
}
// Automatically start CWS when running on a server (Linux OS, Virtual Control)
Debug.Console(DebugTrace, Debug.ErrorLogLevel.Notice, "Starting Essentials Web API on Virtual Control Server");
_server.Start();
GetPaths();
}
/// <summary>
/// Print the available pahts
/// </summary>
/// <example>
/// http(s)://{ipaddress}/cws/{basePath}
/// http(s)://{ipaddress}/VirtualControl/Rooms/{roomId}/cws/{basePath}
/// </example>
public void GetPaths()
{
Debug.Console(DebugTrace, this, "{0}", new String('-', 50));
var currentIp = CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostname = CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var path = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server
? string.Format("http(s)://{0}/VirtualControl/Rooms/{1}/cws{2}", hostname, InitialParametersClass.RoomId, BasePath)
: string.Format("http(s)://{0}/cws{1}", currentIp, BasePath);
Debug.Console(DebugTrace, this, "Server:{0}", path);
var routeCollection = _server.GetRouteCollection();
if (routeCollection == null)
{
Debug.Console(DebugTrace, this, "Server route collection is null");
return;
}
Debug.Console(DebugTrace, this, "Configured Routes:");
foreach (var route in routeCollection)
{
Debug.Console(DebugTrace, this, "{0}: {1}/{2}", route.Name, path, route.Url);
}
Debug.Console(DebugTrace, this, "{0}", new String('-', 50));
}
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core.Web
{
public class EssentialsWebApiFactory : EssentialsDeviceFactory<EssemtialsWebApi>
{
public EssentialsWebApiFactory()
{
TypeNames = new List<string> { "EssentialsWebApi" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create new Essentials Web API Server");
var props = dc.Properties.ToObject<EssentialsWebApiPropertiesConfig>();
if (props != null) return new EssemtialsWebApi(dc.Key, dc.Name, props);
Debug.Console(1, "Factory failed to create new Essentials Web API Server");
return null;
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp.WebScripting;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.Web
{
public class EssentialsWebApiHelpers
{
public static string GetRequestBody(HttpCwsRequest request)
{
var bytes = new Byte[request.ContentLength];
request.InputStream.Read(bytes, 0, request.ContentLength);
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
public static object MapToAssemblyObject(LoadedAssembly assembly)
{
return new
{
Name = assembly.Name,
Version = assembly.Version
};
}
public static object MapToDeviceListObject(IKeyed device)
{
return new
{
Key = device.Key,
Name = (device is IKeyName)
? (device as IKeyName).Name
: "---"
};
}
public static object MapJoinToObject(string key, JoinMapBaseAdvanced join)
{
var kp = new KeyValuePair<string, JoinMapBaseAdvanced>(key, join);
return MapJoinToObject(kp);
}
public static object MapJoinToObject(KeyValuePair<string, JoinMapBaseAdvanced> join)
{
return new
{
DeviceKey = join.Key,
Joins = join.Value.Joins.Select(j => MapJoinDataCompleteToObject(j))
};
}
public static object MapJoinDataCompleteToObject(KeyValuePair<string, JoinDataComplete> joinData)
{
return new
{
Signal = joinData.Key,
Description = joinData.Value.Metadata.Description,
JoinNumber = joinData.Value.JoinNumber,
JoinSpan = joinData.Value.JoinSpan,
JoinType = joinData.Value.Metadata.JoinType.ToString(),
JoinCapabilities = joinData.Value.Metadata.JoinCapabilities.ToString()
};
}
public static object MapDeviceTypeToObject(string key, DeviceFactoryWrapper device)
{
var kp = new KeyValuePair<string, DeviceFactoryWrapper>(key, device);
return MapDeviceTypeToObject(kp);
}
public static object MapDeviceTypeToObject(KeyValuePair<string, DeviceFactoryWrapper> device)
{
return new
{
Type = device.Key,
Description = device.Value.Description,
CType = device.Value.CType == null ? "---": device.Value.CType.ToString()
};
}
}
}

View File

@@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core.Web
{
public class EssentialsWebApiPropertiesConfig
{
[JsonProperty("basePath")]
public string BasePath { get; set; }
}
}

View File

@@ -0,0 +1,82 @@
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class AppDebugRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public AppDebugRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleGet(HttpCwsContext context)
{
var appDebug = new AppDebug { Level = Debug.Level };
var body = JsonConvert.SerializeObject(appDebug, Formatting.Indented);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.Write(body, false);
context.Response.End();
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePost(HttpCwsContext context)
{
if (context.Request.ContentLength < 0)
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var data = EssentialsWebApiHelpers.GetRequestBody(context.Request);
if (string.IsNullOrEmpty(data))
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var appDebug = new AppDebug();
var requestBody = JsonConvert.DeserializeAnonymousType(data, appDebug);
Debug.SetDebugLevel(requestBody.Level);
appDebug.Level = Debug.Level;
var responseBody = JsonConvert.SerializeObject(appDebug, Formatting.Indented);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.Write(responseBody, false);
context.Response.End();
}
}
public class AppDebug
{
[JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)]
public int Level { get; set; }
}
}

View File

@@ -0,0 +1,118 @@
using Crestron.SimplSharp.WebScripting;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class DefaultRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public DefaultRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles CONNECT method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleConnect(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles DELETE method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleDelete(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleGet(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles HEAD method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleHead(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles OPTIONS method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleOptions(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles PATCH method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePatch(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePost(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles PUT method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePut(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
/// <summary>
/// Handles TRACE method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleTrace(HttpCwsContext context)
{
context.Response.StatusCode = 418;
context.Response.StatusDescription = "I'm a teapot";
context.Response.End();
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using Crestron.SimplSharp.WebScripting;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class DevJsonRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public DevJsonRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePost(HttpCwsContext context)
{
if (context.Request.ContentLength < 0)
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var data = EssentialsWebApiHelpers.GetRequestBody(context.Request);
if (string.IsNullOrEmpty(data))
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
try
{
DeviceJsonApi.DoDeviceActionWithJson(data);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.End();
}
catch (Exception ex)
{
Debug.Console(1, "Exception Message: {0}", ex.Message);
Debug.Console(2, "Exception Stack Trace: {0}", ex.StackTrace);
if(ex.InnerException != null) Debug.Console(2, "Exception Inner: {0}", ex.InnerException);
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
}
}
}
}

View File

@@ -0,0 +1,51 @@
using System.Linq;
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class DevListRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public DevListRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleGet(HttpCwsContext context)
{
var allDevices = DeviceManager.AllDevices;
if (allDevices == null)
{
context.Response.StatusCode = 404;
context.Response.StatusDescription = "Not Found";
context.Response.End();
return;
}
allDevices.Sort((a, b) => System.String.Compare(a.Key, b.Key, System.StringComparison.Ordinal));
var deviceList = allDevices.Select(d => EssentialsWebApiHelpers.MapToDeviceListObject(d)).ToList();
var js = JsonConvert.SerializeObject(deviceList, Formatting.Indented);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.Write(js, false);
context.Response.End();
}
}
}

View File

@@ -0,0 +1,76 @@
using System.Text;
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class DevPropsRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public DevPropsRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePost(HttpCwsContext context)
{
if (context.Request.ContentLength < 0)
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var data = EssentialsWebApiHelpers.GetRequestBody(context.Request);
if (string.IsNullOrEmpty(data))
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var o = new DeviceActionWrapper();
var body = JsonConvert.DeserializeAnonymousType(data, o);
if (string.IsNullOrEmpty(body.DeviceKey))
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var deviceProps = DeviceJsonApi.GetProperties(body.DeviceKey);
if (deviceProps == null || deviceProps.ToLower().Contains("no device"))
{
context.Response.StatusCode = 404;
context.Response.StatusDescription = "Not Found";
context.Response.End();
return;
}
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Write(deviceProps, false);
context.Response.End();
}
}
}

View File

@@ -0,0 +1,32 @@
using Crestron.SimplSharp.WebScripting;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class DisableAllStreamDebugRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public DisableAllStreamDebugRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected override void HandlePost(HttpCwsContext context)
{
DeviceManager.DisableAllDeviceStreamDebugging();
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.End();
}
}
}

View File

@@ -0,0 +1,102 @@
using System.Linq;
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Essentials.Core.Web.RequestHandlers
{
public class GetFeedbacksForDeviceRequestHandler : WebApiBaseRequestHandler
{
/// <summary>
/// Constructor
/// </summary>
/// <remarks>
/// base(true) enables CORS support by default
/// </remarks>
public GetFeedbacksForDeviceRequestHandler()
: base(true)
{
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected override void HandleGet(HttpCwsContext context)
{
var routeData = context.Request.RouteData;
if (routeData == null)
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
object deviceObj;
if (!routeData.Values.TryGetValue("deviceKey", out deviceObj))
{
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Bad Request";
context.Response.End();
return;
}
var device = DeviceManager.GetDeviceForKey(deviceObj.ToString()) as IHasFeedback;
if (device == null)
{
context.Response.StatusCode = 404;
context.Response.StatusDescription = "Not Found";
context.Response.End();
return;
}
var boolFeedback =
from feedback in device.Feedbacks.OfType<BoolFeedback>()
where !string.IsNullOrEmpty(feedback.Key)
select new
{
FeedbackKey = feedback.Key,
Value = feedback.BoolValue
};
var intFeedback =
from feedback in device.Feedbacks.OfType<IntFeedback>()
where !string.IsNullOrEmpty(feedback.Key)
select new
{
FeedbackKey = feedback.Key,
Value = feedback.IntValue
};
var stringFeedback =
from feedback in device.Feedbacks.OfType<StringFeedback>()
where !string.IsNullOrEmpty(feedback.Key)
select new
{
FeedbackKey = feedback.Key,
Value = feedback.StringValue ?? string.Empty
};
var responseObj = new
{
BoolValues = boolFeedback,
IntValues = intFeedback,
SerialValues = stringFeedback
};
var js = JsonConvert.SerializeObject(responseObj, Formatting.Indented);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
context.Response.ContentType = "application/json";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.Write(js, false);
context.Response.End();
}
}
}

Some files were not shown because too many files have changed in this diff Show More