From 615880a3d862eda828ffe7417b11c1ac69ccc863 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 26 Jun 2017 10:11:12 -0600 Subject: [PATCH] Working 2-way communication with Cotija Node server for Essentials Huddle Room Type --- .../Display/MockDisplay.cs | 322 +++++++++--------- .../PepperDash_Essentials_Core.projectinfo | Bin 1287 -> 1286 bytes .../Essentials_DM/Essentials_DM.projectinfo | Bin 1139 -> 1135 bytes .../Display/NECPSXMDisplay.cs | 10 +- .../Essentials Devices Common.projectinfo | Bin 1164 -> 1158 bytes .../Config/DeviceFactory.cs | 129 +++---- .../PepperDashEssentials/ControlSystem.cs | 2 + .../PepperDashEssentials.projectinfo | Bin 1858 -> 1855 bytes .../Room/Cotija/CotijaRoomBridge.cs | 226 ++++++++++++ .../Room/Cotija/CotijaSystemController.cs | 119 +++++-- .../Room/EssentialsHuddleSpaceRoom.cs | 27 +- .../UI/EssentialsTouchpanelController.cs | 2 +- 12 files changed, 572 insertions(+), 265 deletions(-) create mode 100644 Essentials/PepperDashEssentials/Room/Cotija/CotijaRoomBridge.cs diff --git a/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs b/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs index 7e6708da..bffea411 100644 --- a/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs +++ b/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs @@ -1,157 +1,167 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DM; -using Crestron.SimplSharpPro.DM.Endpoints; -using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; - -using PepperDash.Core; -using PepperDash.Essentials.Core.Routing; - - -namespace PepperDash.Essentials.Core -{ - /// - /// - /// - public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback - - { - public RoutingInputPort HdmiIn1 { get; private set; } - public RoutingInputPort HdmiIn2 { get; private set; } - public RoutingInputPort HdmiIn3 { get; private set; } - public RoutingInputPort ComponentIn1 { get; private set; } - public RoutingInputPort VgaIn1 { get; private set; } - - bool _PowerIsOn; - bool _IsWarmingUp; - bool _IsCoolingDown; - - protected override Func PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } } - protected override Func IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } } - protected override Func IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } } - - ushort _FakeVolumeLevel = 31768; - bool _IsMuted; - - public MockDisplay(string key, string name) - : base(key, name) - { - HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, null, this); - HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, null, this); - HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, null, this); - ComponentIn1 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Video, - eRoutingPortConnectionType.Component, null, this); - VgaIn1 = new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video, - eRoutingPortConnectionType.Composite, null, this); - InputPorts.AddRange(new[] { HdmiIn1, HdmiIn2, HdmiIn3, ComponentIn1, VgaIn1 }); - - VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; }); - MuteFeedback = new BoolFeedback(CommonBoolCue.MuteOn, () => _IsMuted); - } - - public override void PowerOn() - { - if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) - { - _IsWarmingUp = true; - IsWarmingUpFeedback.FireUpdate(); - // Fake power-up cycle - WarmupTimer = new CTimer(o => - { - _IsWarmingUp = false; - _PowerIsOn = true; - IsWarmingUpFeedback.FireUpdate(); - PowerIsOnFeedback.FireUpdate(); - }, WarmupTime); - } - } - - public override void PowerOff() - { - // If a display has unreliable-power off feedback, just override this and - // remove this check. - if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) - { - _IsCoolingDown = true; - _PowerIsOn = false; - PowerIsOnFeedback.FireUpdate(); - IsCoolingDownFeedback.FireUpdate(); - // Fake cool-down cycle - CooldownTimer = new CTimer(o => - { - Debug.Console(2, this, "Cooldown timer ending"); - _IsCoolingDown = false; - IsCoolingDownFeedback.FireUpdate(); - }, CooldownTime); - } - } - - public override void PowerToggle() - { - if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) - PowerOff(); - else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) - PowerOn(); - } - - public override void ExecuteSwitch(object selector) - { - Debug.Console(2, this, "ExecuteSwitch: {0}", selector); - } - - - - #region IBasicVolumeWithFeedback Members - - public IntFeedback VolumeLevelFeedback { get; private set; } - - public void SetVolume(ushort level) - { - _FakeVolumeLevel = level; - VolumeLevelFeedback.FireUpdate(); - } - - public void MuteOn() - { - _IsMuted = true; - MuteFeedback.FireUpdate(); - } - - public void MuteOff() - { - _IsMuted = false; - MuteFeedback.FireUpdate(); - } - - public BoolFeedback MuteFeedback { get; private set; } - - #endregion - - #region IBasicVolumeControls Members - - public void VolumeUp(bool pressRelease) - { - Debug.Console(0, this, "Volume Down {0}", pressRelease); - } - - public void VolumeDown(bool pressRelease) - { - Debug.Console(0, this, "Volume Up {0}", pressRelease); - } - - public void MuteToggle() - { - _IsMuted = !_IsMuted; - MuteFeedback.FireUpdate(); - } - - #endregion - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DM; +using Crestron.SimplSharpPro.DM.Endpoints; +using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; + +using PepperDash.Core; +using PepperDash.Essentials.Core.Routing; + + +namespace PepperDash.Essentials.Core +{ + /// + /// + /// + public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback + + { + public RoutingInputPort HdmiIn1 { get; private set; } + public RoutingInputPort HdmiIn2 { get; private set; } + public RoutingInputPort HdmiIn3 { get; private set; } + public RoutingInputPort ComponentIn1 { get; private set; } + public RoutingInputPort VgaIn1 { get; private set; } + + bool _PowerIsOn; + bool _IsWarmingUp; + bool _IsCoolingDown; + + protected override Func PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } } + protected override Func IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } } + protected override Func IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } } + + ushort _FakeVolumeLevel = 31768; + bool _IsMuted; + + public MockDisplay(string key, string name) + : base(key, name) + { + HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, null, this); + HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, null, this); + HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, null, this); + ComponentIn1 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Video, + eRoutingPortConnectionType.Component, null, this); + VgaIn1 = new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video, + eRoutingPortConnectionType.Composite, null, this); + InputPorts.AddRange(new[] { HdmiIn1, HdmiIn2, HdmiIn3, ComponentIn1, VgaIn1 }); + + VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; }); + MuteFeedback = new BoolFeedback(CommonBoolCue.MuteOn, () => _IsMuted); + } + + public override void PowerOn() + { + if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) + { + _IsWarmingUp = true; + IsWarmingUpFeedback.FireUpdate(); + // Fake power-up cycle + WarmupTimer = new CTimer(o => + { + _IsWarmingUp = false; + _PowerIsOn = true; + IsWarmingUpFeedback.FireUpdate(); + PowerIsOnFeedback.FireUpdate(); + }, WarmupTime); + } + } + + public override void PowerOff() + { + // If a display has unreliable-power off feedback, just override this and + // remove this check. + if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) + { + _IsCoolingDown = true; + _PowerIsOn = false; + PowerIsOnFeedback.FireUpdate(); + IsCoolingDownFeedback.FireUpdate(); + // Fake cool-down cycle + CooldownTimer = new CTimer(o => + { + Debug.Console(2, this, "Cooldown timer ending"); + _IsCoolingDown = false; + IsCoolingDownFeedback.FireUpdate(); + }, CooldownTime); + } + } + + public override void PowerToggle() + { + if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) + PowerOff(); + else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) + PowerOn(); + } + + public override void ExecuteSwitch(object selector) + { + Debug.Console(2, this, "ExecuteSwitch: {0}", selector); + } + + + + #region IBasicVolumeWithFeedback Members + + public IntFeedback VolumeLevelFeedback { get; private set; } + + public void SetVolume(ushort level) + { + _FakeVolumeLevel = level; + VolumeLevelFeedback.FireUpdate(); + } + + public void MuteOn() + { + _IsMuted = true; + MuteFeedback.FireUpdate(); + } + + public void MuteOff() + { + _IsMuted = false; + MuteFeedback.FireUpdate(); + } + + public BoolFeedback MuteFeedback { get; private set; } + + #endregion + + #region IBasicVolumeControls Members + + public void VolumeUp(bool pressRelease) + { + Debug.Console(2, this, "Volume Down {0}", pressRelease); + if (pressRelease) + { + var newLevel = _FakeVolumeLevel + 655; + SetVolume((ushort)newLevel); + } + } + + public void VolumeDown(bool pressRelease) + { + Debug.Console(2, this, "Volume Up {0}", pressRelease); + if (pressRelease) + { + var newLevel = _FakeVolumeLevel - 655; + SetVolume((ushort)newLevel); + } + } + + public void MuteToggle() + { + _IsMuted = !_IsMuted; + MuteFeedback.FireUpdate(); + } + + #endregion + } } \ No newline at end of file diff --git a/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.projectinfo b/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.projectinfo index aedc307daf0c36e4dec7a7ba6d2b75b35d3fa13e..9fdf18f46f447e4158ac4906f19139548e94edcf 100644 GIT binary patch delta 726 zcmV;{0xA863Wf@hynnrWZ+7oLy7%DG-lyYF_debI^x-}F_|eV|wVPABlSjYr@B7`V zep@Ur(x*k8Pur?4^5*ybeO-UQ@9+Ei$A917H@BVszQ3*}Woi?ii<^{goKWwywF2xxA=a3u&8gntkrde%_)?X{V@*Vj#( zFJ1_e8>fiIbx~)Fv)P;M;+Aa}c`XxqJew75Q7y9)WRcHKs>O=vGy8IR%h@(B{1B;n z%gH}oO!C?5YF$tB<9a$TE_2HbC)MiuP4%oQXL;Rx^vDR(-bcS=^wAf^vRJGa&x(3+ zmDTxAQVXIH#D8qOv-6PtzxR-Uf4Oc~>-J^V{_Jx*_4Y-!EY9<$b*SE>PjBQ8Ly0f4 zVtGtoEhgo)1F=uvc(b+v%&aV_Z9ob7Z|~E4dwU=C2-c<4w+SMBHrv_Ve>k0FlTY)9 zpFVt;-J9)B9^5;a-23$2Y;E@T(7mAvdi@j6znz!V%fS4c?@aIS+@HFgkTaBy$7KY4I}Z}-9do!#kV z@?cLd!>*q&x>Hl9jlt(%>Ly`9OYyVL!H=|Q$P zrNJKTJ-q)Q&u7H$_Z~c$4j7Uc4R1~C4lN_-{gUthl3&94i{f1UUK;1RY-QO059zBB Ik4F^%0L-zL-v9sr delta 727 zcmV;|0x1243Wo}iyno$?Z+1U@bpPPd{k`$S`#YcR?(NaXk9Kyb-JIH;Jo-zhBf8WyEx$X4#{e2w*DG=}*yRV*P4Sh2ymj2gW z+{e>Z`2#|wuvB?jS3gZyoGs6*XGNJWvqk(&bE2she*|1 zPX6g)lFwdO>w20W*VB1%nOkl+saDr-s%KR>%j@Q&M@EqLKKdo2kG?3D#bUj9R@95D ztj>RuS`dvOW`E$O z%VYX#F)6Pdh<*CTo3#yKW@Slj14__;d-v|&0|#^n)}_?92_k*A^Wfg>)BBU@!Ka_@ zeR}@s!QR8&2M=~Xoy{I-YF zorlx=vwJ(UET7G0=LZk(Pw#!2O(*BsG~b!s_i4WYS}*~(fO*Ra*wEwun`dEfXck`O z=Ox1KYI(M7^BRBj2&W^zcYc15&nA=XV1GKDJ=nc}fAa9*!G8YfgZ+bpN#I7`25c}d zw*da$^D^A^|C=Z1-p~ZS{)y+`&P(cLV1CYbruTR5&t~~_c91e=t4B z_NFvgiu3P3$nzPo`@IJbrUQl~M#EbZyF<$edcWlRzvP#2{-QWnzn8|jE?XJ){{!2z J3kgRR002*UnT!Ac diff --git a/Essentials DM/Essentials_DM/Essentials_DM.projectinfo b/Essentials DM/Essentials_DM/Essentials_DM.projectinfo index 0c8e39d275e5daedae369ad1bfc8c9e017c04d21..3811ad6a92d71ad67dfca18d4c695b2f238fc8ae 100644 GIT binary patch delta 972 zcmV;-12g>d2=54xv43~(&F=k2_Z~dDcW->}-tOMs-lz2Oqn#aUH>Y+dkAC0Z_q$d7 zwpd=IPm4OAwpCr^&F}mBzRXvvyndQB^WXRPef{IV@9&%2E`Q(O*L9yh{lfqA_s5@; zV%hm@JYAJPpbiT=!k2aR)7015^1OOhl=(7SZH9k#D0C< zwE5zNpwgu|*%qMPADk9M5J&TU5)e#1Q4PlWMV|vCh6+-g17-3qQLQ z8lJAx#U!7-uGaN5Kdz_q;xf1McT%mc-&D`4a+cT4M~@5}?|t-3Mjw4qEQ`f@@vNv9 zS6Q9^B()$)fPcxyJ39~Q|9cM!_?PQ;wQgT#?avAqQU_mT%i=t5T8G^|`c$Xa!TtTC zL;oTxmdEtPVp3i^0Q>ZfHyMLKW@Sk&gMrh3d!OFhyZ=#-K3&3mo8ZxB_a992{euVR zJD=X4-rKo9%VrOEKi%EQ_Gfv%mp%NHTFTViVl+zSn}3=;ucle~vo#~iXgAR8X}-#r zvwS(FzCL>NJwteq&6k3j=C!Vt={4~ETrupmjYE{*(0#s^Fvn=1A z?C;%wm}Tdm?mpbP|L}Y#%kS;)Ke#tJpY8e7d=KdI&h7iS%|twUkN$u5XRJRb-yePS zDsOn;{D0>!8JSu7^memk=32=%nVsLyrsvtg&UAWjG9i}V+nwc;gNM7jdk2%<*=?rA zfDGp27Jxr!K1`?o@0x@MgF5P@s`HTadk^ms!|r@~Z)gAE?Eb;z)B6t}PV($i{w&LP zeA34O1q8nZxLXlC-qruR$b4`cQ_!dQY-e}>;eT|JO+L*Ze){lXc5k*jd2sJwa_`f7 zv+2R^EwuU&@oxe7eTg6M_5WS-0E_9(gA>sg`Bhsjo9et{2_8;&9!~Gi?(NL7d^Ve% zA3P-c`e`e9YBrFCdNKAjz84-W3l_9qYS@9jRgzq31?OdbqO$RN~UK5hZ~ zJ?CSv-~U%kN9O}OIeSBs^E7L-@hofIbVVHO?My!1o$en@53;=}jqhOZ;r$1BJ|l*{ u_u#?wW()B_et!hDU-JE5@=G|HDb9;&22r3fuFF=2{Qm$``R}m85C8xQuPA8% delta 976 zcmV;>126pV2=fS#v48vU&F-gLPD`-{1FTzFOt=)2x~QzQ6D5AOC%S-`sZj`~JSJ`}FA-{-3`;{+txc z&S&H4s{8?USlAK1tgD}+7b? z7cT^rE`MZLJn z>ij3E1yKS_K7ZcXc}V}?dq}{)T(_%r`!Z{PR=AKl_##^t=XujQ?C#O0I=v3=?;jod z7g@19rY{zg^4bB|r*FK;7z8paOKKSmoc`N8c<|}LM?Ly<3G;1&N1sg}PG;HkVD~|` zKixZ+96Y%9aBuc$HhYj|dwct{8MTzDxy5Ld$~QH8UVlxq@@H#Cl+kXW+0%TLFK793 zN_~Cw=zE6n_d~*;)HJVkwH&`L7OV30JgZkEfa9n6WiicPuUD(8ZWW-RW|rmqll{H> z53}t2)7^(V_aC0`Wcj`Q{Rj6Z=d(SZn(qN!-no4rx0#4X@6rFy{*3kKwkCbRSV+4MX+*qKi6O^DIY_jYIb`d|p`wwOZ_on&&`Mur!>HXdPz3Dxl z^l?A|!EXWXRs@fC_5Ut19}JS&gWIS0&VzfiPk--ErU##Xy7%e%rw4lvcON|1{d6+> zbZ770r+fPY6pzCUh<^*n?@Ro6umA6whlk-jI1zo3U$xb;sm?o=;Nf)V;q?CO-p(w` zXS3P)!NdF0d!J_0$$2)-cV_qf8Q1_Vp#3di-ir1c`ul$u)pvJ>$o?unFX3TV%d=&h z*MA^DNdNra`T0RUn@qBU{pob}VE6w0$-{>S`}wC2_74swfhE2T*kB@V0sK8DVz}e~ zm(9rT(2TtPiRa(WOTuDcLe6)l_jm5kX8Ck>kUcoKH`|{)xWBji;Qr3;bTWA`Fd>6b zgZa1x?Dw3H!G8Z=F&&)`?BwhXP0rJ-%}K_ytaa0Iu(vb$ba%RcFg?ijrZhg%TGc~dy`!RO@q1BR*Srr**%`kingehSqaL>X9RLZB$|D>yyeuJ7k+LCdpk}z zT}<-X>uOz3^W%CtFD`S-8Yk82`c3t$Drb4!eDuf&*4{_IWc1M&#j;qe7te}%ah28i zPf`n_7Q}A6vw!oD{=fH-fPcAeSL^m=*8Wh1fI9vnTNdYe(>kp0(Wf_Yi=oLES+P8( zMvF;#?I7&aH{MJRLz$H&H4R8Y|LuKxZx2XxDAy&~w}}iO^21LLc6QFsckk!t2YY*y z-TQl=-k;o~&$4Wi-Os3{OxkV6qZ4pryXVz3D}UItb$=tH3OS$Vt9&`jms3LGqetH} zlX5?tl#`k!y{4C57mHQ-dY;uQlI*cSe7#<+s=8HxO6X~p<@=NUz55Td?EKT+hdcKl zp6_J&z5V?M_a^7FJ)h9;0bSm?eIK`)qDSw6z|Y-W_9yH6qmN$Y4O4{w{3RnZeV^WH z`aaLv{3t5BZo-*+u(!XL@9pko*}a4PdwY8a+5OqW-F))trw4lv&kq6-xgC?~0vmt! z9^NCS-}&_3&i=#M{e#J;_a8o-r zVz#rp|8P3VCZFaHKYjQxyEogNJh*o-x%cV4+4Nxd(}Ago!whES7Leb2R^r|Me`A7R z!o3M{BL5=4YO7^aopHUA%y`5Q>&t|jpgNOI0_dd<0lk;qv@67J|Q?mhD zFe$fydAmv3(Bc0#rek+!Xg*%$=Ou!RYI(M7^BR;1CnmpletwY8CX?)7e>$B#*u8&$ z^6=roe*Wo${ey!^;27KnY%oK&0RFx+G~Dz5N2Y3bXsTZS#Pe_GC1E!(Q|Es>)B8L3 zXR~}dJIEd!+?(xB9^BvCeQhGy+) z)@I{b*1CB**xQ+Wx;x!Jm>y(%QyMopQuiO^`HV#1-h&5If1Wl|^R`s)5H*6_FZup2 f`6V2y73ak?gY?iS*JUe%{(lJob=fUZOcDS9`TZI& delta 985 zcmV;~119{235*Gl!GF6C-|T++=>EZ@`=5?K{q+9cgL@C@<3~F?)NW4gP9FWfzwdXe z`fahiNS_vUK5eVI$eZ8y_kEeKR(bt2Yv#Z2@B8}4f8XCXw>|&9zwaQH8^4+qo4y}U zSLF`~slpQGWnKL=;d8b;ubvfUzRVW+4;SHKTvvixL8uYRXMYVL(q5Z+e0|-t`QnA3 zyJuUd!wr&t^qiRLiUcW#lsgxgrwHzFgjN>dgy3H-x<% zC!8)O`RsMIuBZ8NJ)IYqxn+%$YIXgldRCRQyly^vWCUyPqhB)m=!;@mEY^!>MZLJn z>ij3E1yKuPH-FyQc}V}?dq}{)T(_%r`!Z{Ps6s#;e~~SV^So&t*7xYso4Cc$;$Gb#7ONja%$(rbF@b+K5Lujg64BFP>L#MkT9s;XNBsDz$oS-wBn-@E@X%g#UD zeYit(-^ucO`}+^>P0nX~KB3p?hQ4xiuuq^k39em^#_+HW#{;L}g{K0OBm?>>02 z`{`u%>CWE0Pxtl*rXmhAn3Y>Ve(za{cl-a133?b#kQ4bA`Bhsjo9et{e;!VE9!~Gi z?(NL7d^Ve%A3VH2z4vK0ot$UWd}nswpPCKOf=Rgr%-c=Mh7SL~F&(=*L-X+}KQ9qn zRDa8}Wt-QaOgJ(5z4P;fd^VY62m90M?7{B+`;&(c5BBpxUq6RzufAu_dKCrX4H&QffPqQ`~&$8Cd)4|@(qg( - properties.ToString()); - return new EssentialsTouchpanelController(key, name, typeName, props, comm.IpIdInt); - } - else if (typeName == "mockdisplay") - { - return new MockDisplay(key, name); - } - - // MOVE into something else??? - else if (typeName == "basicirdisplay") - { - var ir = IRPortHelper.GetIrPort(properties); - if (ir != null) - return new BasicIrDisplay(key, name, ir.Port, ir.FileName); - } - - else if (typeName == "commmock") - { - var comm = CommFactory.CreateCommForDevice(dc); - var props = JsonConvert.DeserializeObject( - properties.ToString()); - return new ConsoleCommMockDevice(key, name, props, comm); +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; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials +{ + public class DeviceFactory + { + public static IKeyed GetDevice(DeviceConfig dc) + { + var key = dc.Key; + var name = dc.Name; + var type = dc.Type; + var properties = dc.Properties; + + var typeName = dc.Type.ToLower(); + + if (typeName == "amplifier") + { + return new Amplifier(dc.Key, dc.Name); + } + else if (dc.Group.ToLower() == "touchpanel") // typeName.StartsWith("tsw")) + { + var comm = CommFactory.GetControlPropertiesConfig(dc); + + var props = JsonConvert.DeserializeObject( + properties.ToString()); + return new EssentialsTouchpanelController(key, name, typeName, props, comm.IpIdInt); + } + else if (typeName == "mockdisplay") + { + return new MockDisplay(key, name); + } + + else if (typeName == "generic") + { + return new Device(key, name); + } + + // MOVE into something else??? + else if (typeName == "basicirdisplay") + { + var ir = IRPortHelper.GetIrPort(properties); + if (ir != null) + return new BasicIrDisplay(key, name, ir.Port, ir.FileName); + } + + else if (typeName == "commmock") + { + var comm = CommFactory.CreateCommForDevice(dc); + var props = JsonConvert.DeserializeObject( + properties.ToString()); + return new ConsoleCommMockDevice(key, name, props, comm); } else if (typeName == "webserver") { var props = JsonConvert.DeserializeObject(properties.ToString()); return new CotijaSystemController(key, name, props); - } - - return null; - } - } -} + } + + return null; + } + } +} diff --git a/Essentials/PepperDashEssentials/ControlSystem.cs b/Essentials/PepperDashEssentials/ControlSystem.cs index 4a270d62..6cba22e5 100644 --- a/Essentials/PepperDashEssentials/ControlSystem.cs +++ b/Essentials/PepperDashEssentials/ControlSystem.cs @@ -162,6 +162,8 @@ namespace PepperDash.Essentials { if (room is EssentialsHuddleSpaceRoom) { + DeviceManager.AddDevice(room); + Debug.Console(1, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion"); DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemController((EssentialsHuddleSpaceRoom)room, 0xf1)); diff --git a/Essentials/PepperDashEssentials/PepperDashEssentials.projectinfo b/Essentials/PepperDashEssentials/PepperDashEssentials.projectinfo index b9a1020ba8e8df3518c5758f9f73d2dfc9feb4c7..a3945a8e2a3d09fd81ac25f562f689956c328a43 100644 GIT binary patch delta 1327 zcmV+~1J`b}_-TGwO!L?4)vBsn z1*kNfW?8;J+24P=|1itWKiz$}bN}J_PL|)>-+yp#az5MhY4{${<(=F2al;%udXKJu zIFr?%lJAc`dX+akZvOL^jLal`db>&bBAl7Y?EHQ+pIRLvK zOm=6tnHd8zn2uWj{<_m)`ul(196Y$y9GtfEyk6!l*_MCBdRa^}SScfdO1^ua=AV9g zZ~x(g-G}#g_jmIA)AQZQemK2`S&AHl$!~gr{@8DMR_iPPw z63*A&G@pFBe?Obu&$69|2j>qCru&mmrw>29m!0p;&TpgP0!4{PbY&;rT&!iy7$v4(8+* z;J@aabb9@N->mHJ+-h20<%_D#JF`Lz`)R&2*}J#1zxOcz^x@ugcJKa9KK=CG^x@8f zNq&o23E>8latr8Rb5g=i|6e#KySJK?ug=2h*g1cAc#n8^XFA!L?BBolVCTW!j1>Rg zz5V>bZoYGy>98P!nYabuuQ?O8zyB9b!d^HD4pb^WWRt=W_H4()PY-r>&d+!6=jR7| zdz0P!d!OE)+@sI3Y?9p%G}TQYL%VS^;F~7lrvCn4I0^T{NpL_X+}J{zxQCew{!pC-lx+~^Lyv#2M_a|U=D787)-$};NCO^H+1*^!WkG0 z&3}K4pv(OCC~DjJlvMV^+5Lmbr}rN|oaEW3{8^Uo#0l>M>ahHc;BHTEznA|PlDQL> zdw4sj5sJ@tcK07nC)woF{Nbk$A7=MvyOVzh_YNlaKD{@a9_$VzGzMS>#J>gP_aJ_} z!~Yk~Lnrc%51|`)-+wU8_bDpg`Skwu-p>75M&9G6yF1zbEYJ6{hqsu8c-(ypxL5Y}w}Zc{c5e!)*V-!`>nIVf^2FRYz%BL0k;5t`w18x%Kr-|q!SstQM~?% z=Nt9?`Ofq{`I57IIy=Z79Ne4jPafPSp1r@bJDp4(49v$M)KDI7hG2dB=@{(t|24DG z`M}OiCuVj-dYZM_c$T$pHb`eoKHZ(}A50Ijy(x{6GS2rOEe;JNx5L5B5Gi;IYXf0e=S%9$;=er0LS++XRa~ zJ9xM^yT7x$^Duw-aQ|Vxvp3m$FxkDgH@SCjy0@F%r)mgo#*v3Z-2?QEY{0nn!!pL5mfTs`!xUb z(|h|5AM8H7zq`Ma=bxVMPWJQ3^!~l``+4@@7W1;Pn_#YP(b?CWtBpAPzi<8yZZ&_; z)-WgGeC+$BPii}&#SAiKqkbN~l) zatrWZb51(F{=aWlc6V+yEwA!L)#ja9A%^`l-7JiIfV>`eCW-+Qq0U~fi> zfA8LY{$MxXxy^J~kiksc0`S+I3ESWQ3nyVOoCF6d6(6!mVFh5%Bws-I; zsrCowpH6otyLUg`ul(3B-{%p!2vy~>ii|S@LBo# zdVe_$=ip&BxtC9;8S&`;-h=7h&i#XXpH4r`@136?P|z1xiyI&YQ*aBoH%-9}-Tl9C z1_nd(-yb6g3IFMg;^@iF&V!vv{$T&X?BL!s-#@>%yFVpYbZ>euPIwE8_bJ%}Ig@c)JL(22a`L+A$H(}$B;HlAjtY)BS9+oA2#UDJ=FU;&y;T8+?;<1tSzt-47?9-oKxnKit{b{WPCVGh*qJtOYfH zkj4FUfB*h$8Yr)uK!yR_&46z|9r6DD-!}<+op{=f;6;AbQogJ@@8r`TPDzQ}pWWM; z5y56NawYFi?|qt0Cm83>ELfA+0IeelH^RI<>3d!MzmV#kh&hZh^LM!;_c{48IR&i` zKc(n(cCfcYnVU=gMs-Ngc{1j&9HA>KOKWz z{=a56Iv?1%*&mvlr&*hgXIblJgLKB^)7|O*!So>8o6;C5(7OL1&&iFM-h1$1>d(dy o&2FY@hiDOme#!TL$uHs6_2OJtc4%blvXz1UKQEGL#E2sR069eX?*IS* diff --git a/Essentials/PepperDashEssentials/Room/Cotija/CotijaRoomBridge.cs b/Essentials/PepperDashEssentials/Room/Cotija/CotijaRoomBridge.cs new file mode 100644 index 00000000..570216f4 --- /dev/null +++ b/Essentials/PepperDashEssentials/Room/Cotija/CotijaRoomBridge.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials +{ + public class CotijaEssentialsHuddleSpaceRoomBridge + { + CotijaSystemController Parent; + + public EssentialsHuddleSpaceRoom Room { get; private set; } + + public CotijaEssentialsHuddleSpaceRoomBridge(CotijaSystemController parent, EssentialsHuddleSpaceRoom room) + { + Parent = parent; + Room = room; + + // Source Changes and room off + Parent.AddAction(string.Format(@"/room/{0}/status",Room.Key), new Action(() => Room_RoomFullStatus(Room))); + Parent.AddAction(string.Format(@"/room/{0}/source", Room.Key), new Action(c => room.RunRouteAction(c.SourceSelect))); + Parent.AddAction(string.Format(@"/room/{0}/event/masterVolumeUpBtn", Room.Key), new Action(b => room.CurrentVolumeControls.VolumeUp(b))); + Parent.AddAction(string.Format(@"/room/{0}/event/masterVolumeDownBtn", Room.Key), new Action(b => room.CurrentVolumeControls.VolumeDown(b))); + Parent.AddAction(string.Format(@"/room/{0}/event/muteToggle", Room.Key), new Action(() => room.CurrentVolumeControls.MuteToggle())); + + Room.CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange); + + Room.CurrentVolumeDeviceChange += new EventHandler(Room_CurrentVolumeDeviceChange); + + Room.OnFeedback.OutputChange += new EventHandler(OnFeedback_OutputChange); + + // Registers for initial volume events, if possible + var currentVolumeDevice = Room.CurrentVolumeControls; + + if (currentVolumeDevice != null) + { + if (currentVolumeDevice is IBasicVolumeWithFeedback) + { + var newDev = currentVolumeDevice as IBasicVolumeWithFeedback; + + newDev.MuteFeedback.OutputChange += new EventHandler(VolumeLevelFeedback_OutputChange); + newDev.VolumeLevelFeedback.OutputChange += new EventHandler(VolumeLevelFeedback_OutputChange); + } + } + + } + + void OnFeedback_OutputChange(object sender, EventArgs e) + { + /* Example message + * { + "type":"/room/status", + "content": { + "isOn": false + } + } + */ + + JObject roomStatus = new JObject(); + + roomStatus.Add("isOn", (sender as BoolFeedback).BoolValue); + + JObject message = new JObject(); + + message.Add("type", "/room/status/"); + message.Add("content", roomStatus); + + Parent.PostToServer(Room, message); + } + + void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) + { + if (e.OldDev is IBasicVolumeWithFeedback) + { + var oldDev = e.OldDev as IBasicVolumeWithFeedback; + + oldDev.MuteFeedback.OutputChange -= VolumeLevelFeedback_OutputChange; + oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange; + } + + if (e.NewDev is IBasicVolumeWithFeedback) + { + var newDev = e.NewDev as IBasicVolumeWithFeedback; + + newDev.MuteFeedback.OutputChange += new EventHandler(VolumeLevelFeedback_OutputChange); + newDev.VolumeLevelFeedback.OutputChange += new EventHandler(VolumeLevelFeedback_OutputChange); + } + } + + void VolumeLevelFeedback_OutputChange(object sender, EventArgs e) + { + /* Example message + * { +   "type":"/room/status", +   "content": { +     "masterVolumeLevel": 12345, +     "masterVolumeMuteState": false +   } + } + */ + + var huddleRoom = Room as EssentialsHuddleSpaceRoom; + + if(huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback) + { + JObject roomStatus = new JObject(); + + if (huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback) + { + var currentVolumeConstrols = huddleRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; + roomStatus.Add("masterVolumeLevel", currentVolumeConstrols.VolumeLevelFeedback.IntValue); + roomStatus.Add("masterVolumeMuteState", currentVolumeConstrols.MuteFeedback.BoolValue); + } + + JObject message = new JObject(); + + message.Add("type", "/room/status/"); + message.Add("content", roomStatus); + + Parent.PostToServer(Room, message); + } + } + + void Room_CurrentSingleSourceChange(EssentialsRoomBase room, PepperDash.Essentials.Core.SourceListItem info, ChangeType type) + { + /* Example message + * { +   "type":"/room/status", +   "content": { +     "selectedSourceKey": "off", +   } + } + */ + + if (type != ChangeType.DidChange) + return; + + JObject roomStatus = new JObject(); + + var huddleRoom = room as EssentialsHuddleSpaceRoom; + //roomStatus.Add("isOn", huddleRoom.OnFeedback.BoolValue); + roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey); + + JObject message = new JObject(); + + message.Add("type", "/room/status/"); + message.Add("content", roomStatus); + + Parent.PostToServer(Room, message); + } + + /// + /// Posts the full status of the room to the server + /// + /// + void Room_RoomFullStatus(EssentialsRoomBase room) + { + /* Example message + * { + "type":"/room/status", + "content": { + "selectedSourceKey": "off", + "isOn": false, + "masterVolumeLevel": 50, + "masterVolumeMuteState": false + } + } + */ + + JObject roomStatus = new JObject(); + + var huddleRoom = room as EssentialsHuddleSpaceRoom; + roomStatus.Add("isOn", huddleRoom.OnFeedback.BoolValue); + roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey); + + + if(huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback) + { + var currentVolumeConstrols = huddleRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; + roomStatus.Add("masterVolumeLevel", currentVolumeConstrols.VolumeLevelFeedback.IntValue); + roomStatus.Add("masterVolumeMuteState", currentVolumeConstrols.MuteFeedback.BoolValue); + } + + JObject message = new JObject(); + + message.Add("type", "/room/status/"); + message.Add("content", roomStatus); + + Parent.PostToServer(Room, message); + + } + + } + + public class SourceSelectMessageContent + { + public string Destination { get; set; } + public string SourceSelect { get; set; } + } + + //public class PostMessage + //{ + // [JsonProperty("type")] + // public string Type { get; set; } + + // [JsonProperty("content")] + // public JToken Content { get; set; } + //} + + //public class RoomStatusMessageContent + //{ + // [JsonProperty("selectedSourceKey")] + // public string SelectedSourceKey { get; set; } + // [JsonProperty("isOn")] + // public bool? IsOn { get; set; } + // [JsonProperty("masterVolumeLevel")] + // public int? MasterVolumeLevel { get; set; } + // [JsonProperty("masterVolumeMuteState")] + // public bool? MasterVolumeMuteState { get; set; } + //} + +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/Room/Cotija/CotijaSystemController.cs b/Essentials/PepperDashEssentials/Room/Cotija/CotijaSystemController.cs index 7ac090f2..7ddffbd6 100644 --- a/Essentials/PepperDashEssentials/Room/Cotija/CotijaSystemController.cs +++ b/Essentials/PepperDashEssentials/Room/Cotija/CotijaSystemController.cs @@ -42,18 +42,33 @@ namespace PepperDash.Essentials CotijaRooms = new List(); - CrestronConsole.AddNewConsoleCommand(ConnectSseClient, "InitializeHttpClient", "Initializes a new HTTP client connection to a specified URL", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(RegisterSystemToServer, "InitializeHttpClient", "Initializes a new HTTP client connection to a specified URL", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(DisconnectSseClient, "CloseHttpClient", "Closes the active HTTP client", ConsoleAccessLevelEnum.AccessOperator); AddPostActivationAction(() => RegisterSystemToServer(null)); } + /// + /// Adds an action to the dictionary + /// + /// The path of the API command + /// The action to be triggered by the commmand public void AddAction(string key, object action) { - // This might blow up if an action with that key already exists - ActionDictionary.Add(key, action); + if (!ActionDictionary.ContainsKey(key)) + { + ActionDictionary.Add(key, action); + } + else + { + Debug.Console(1, this, "Cannot add action with key '{0}' because key already exists in ActionDictionary."); + } } + /// + /// Removes and action from the dictionary + /// + /// public void RemoveAction(string key) { if (ActionDictionary.ContainsKey(key)) @@ -135,22 +150,39 @@ namespace PepperDash.Essentials /// object to be serialized and sent in post body public void PostToServer(EssentialsRoomBase room, JObject o) { - if(Client == null) - Client = new HttpClient(); + try + { + if (Client == null) + Client = new HttpClient(); - HttpClientRequest request = new HttpClientRequest(); + //HttpClient client = new HttpClient(); - Client.Verbose = true; - Client.KeepAlive = true; + HttpClientRequest request = new HttpClientRequest(); - string url = string.Format("http://{0}/api/room/{1}", Config.serverUrl, string.Format("{0}-{1}", SystemUuid, room.Key)); + Client.Verbose = true; + Client.KeepAlive = true; - request.Url.Parse(url); - request.RequestType = RequestType.Post; - request.Header.SetHeaderValue("Content-Type", "application/json"); - request.ContentString = o.ToString(); + string url = string.Format("http://{0}/api/room/{1}/status", Config.serverUrl, string.Format("{0}--{1}", SystemUuid, room.Key)); - Client.DispatchAsync(request, PostConnectionCallback); + request.Url.Parse(url); + request.RequestType = RequestType.Post; + request.Header.SetHeaderValue("Content-Type", "application/json"); + request.KeepAlive = true; + + // Ignore any null objects when serializing and remove formatting + string ignored = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + request.ContentString = ignored; + + Debug.Console(1, this, "Posting to '{0}':\n{1}", url, request.ContentString); + + Client.DispatchAsync(request, (r, err) => { if (r != null) { Debug.Console(1, this, "Status Response Code: {0}", r.Code); } }); + + StartReconnectTimer(5000, 5000); + } + catch(Exception e) + { + Debug.Console(1, this, "Error Posting to Server: {0}", e); + } } /// @@ -181,6 +213,13 @@ namespace PepperDash.Essentials { if (resp != null && resp.Code == 200) { + if(Reconnect != null) + { + Reconnect.Stop(); + + Reconnect = null; + } + if (SseClient == null) { ConnectSseClient(null); @@ -188,12 +227,12 @@ namespace PepperDash.Essentials } else { - Debug.Console(0, this, "Unable to initialize SSE Client"); + Debug.Console(0, this, "Response from server: {0}\n{1}", resp.Code, err); } } catch (Exception e) { - Debug.Console(1, this, "Error Initializeing SSE Client: {0}", e); + Debug.Console(1, this, "Error Initializing SSE Client: {0}", e); } } @@ -205,15 +244,22 @@ namespace PepperDash.Essentials { if (Heartbeat != null) { + Debug.Console(1, this, "Heartbeat Timer Expired."); + Heartbeat.Stop(); Heartbeat = null; } - // Start the reconnect timer - Reconnect = new CTimer(ReconnectToServer, null, 5000, 5000); + StartReconnectTimer(5000, 5000); + } - Reconnect.Reset(5000, 5000); + void StartReconnectTimer(long dueTime, long repeatTime) + { + // Start the reconnect timer + Reconnect = new CTimer(ReconnectToServer, null, dueTime, repeatTime); + + Reconnect.Reset(dueTime, repeatTime); } @@ -246,11 +292,8 @@ namespace PepperDash.Essentials SseClient.Url = string.Format("http://{0}/api/system/stream/{1}", Config.serverUrl, uuid); SseClient.Connect(); - - //Heartbeat = new CTimer(HeartbeatExpired, null, 20000, 20000); - - //Heartbeat.Reset(20000, 20000); } + void LineGathered_LineReceived(object sender, GenericCommMethodReceiveTextArgs e) { @@ -260,8 +303,6 @@ namespace PepperDash.Essentials { var message = e.Text.Substring(6); - string roomId = null; - Debug.Console(1, this, "Message: '{0}'", message); try @@ -270,11 +311,21 @@ namespace PepperDash.Essentials var type = messageObj["type"].Value(); - if(type == "/system/hearbeat") + if (type == "hello") { - //Heartbeat.Reset(20000, 20000); + Heartbeat = new CTimer(HeartbeatExpired, null, 20000, 20000); + + Debug.Console(2, this, "Heartbeat Timer Started."); + + Heartbeat.Reset(20000, 20000); } - else if(type == "close") + else if (type == "/system/heartbeat") + { + Heartbeat.Reset(20000, 20000); + + Debug.Console(2, this, "Heartbeat Timer Reset."); + } + else if (type == "close") { SseClient.Disconnect(); @@ -285,19 +336,21 @@ namespace PepperDash.Essentials } else { - - // Check path against Action dictionary if (ActionDictionary.ContainsKey(type)) { var action = ActionDictionary[type]; - if (action is Action) + if (action is Action) + { + (action as Action)(); + } + else if (action is Action) { var stateString = messageObj["content"]["state"].Value(); // Look for a button press event - if(!string.IsNullOrEmpty(stateString)) + if (!string.IsNullOrEmpty(stateString)) { #warning deal with held state later if (stateString == "held") @@ -320,7 +373,7 @@ namespace PepperDash.Essentials .ToObject()); } } - + } } diff --git a/Essentials/PepperDashEssentials/Room/EssentialsHuddleSpaceRoom.cs b/Essentials/PepperDashEssentials/Room/EssentialsHuddleSpaceRoom.cs index 9485ee10..fa7bee4c 100644 --- a/Essentials/PepperDashEssentials/Room/EssentialsHuddleSpaceRoom.cs +++ b/Essentials/PepperDashEssentials/Room/EssentialsHuddleSpaceRoom.cs @@ -80,14 +80,16 @@ namespace PepperDash.Essentials _CurrentSourceInfo = value; - // add to in-use tracking + // add to in-use tracking if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); if (handler != null) handler(this, _CurrentSourceInfo, ChangeType.DidChange); } } - SourceListItem _CurrentSourceInfo; + SourceListItem _CurrentSourceInfo; + + public string CurrentSourceInfoKey { get; private set; } /// /// @@ -154,9 +156,15 @@ namespace PepperDash.Essentials Debug.Console(2, this, "Action {0} has {1} steps", item.SourceKey, item.RouteList.Count); - // Let's run it - if (routeKey.ToLower() != "roomoff") - LastSourceKey = routeKey; + // Let's run it + if (routeKey.ToLower() != "roomoff") + { + LastSourceKey = routeKey; + } + else + { + CurrentSourceInfoKey = null; + } foreach (var route in item.RouteList) { @@ -203,9 +211,12 @@ namespace PepperDash.Essentials } CurrentVolumeControls = volDev; - // store the name and UI info for routes - if (item.SourceKey != null) - CurrentSourceInfo = item; + // store the name and UI info for routes + if (item.SourceKey != null) + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = item; + } // And finally, set the "control". This will trigger event //CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device; diff --git a/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs b/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs index 17321bb3..a6b1f623 100644 --- a/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs +++ b/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs @@ -94,7 +94,7 @@ namespace PepperDash.Essentials var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, props); // Then the AV driver - // spin up different room drivers depending on room type + // spin up different room drivers depending on room type var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey); if (room is EssentialsHuddleSpaceRoom) {