VC-4: Part 3

In the last part, we got an XPanel connected to our VC-4 room and made it change state a little. We aren’t going to add much in this part, just a few changes to make things a little nicer for us.

The first problem you might have noticed is when the XPanel first opens, the background is bright and when you click the Power button, nothing happens. If you click again, the power state catches up and the background goes dim. We should fix this so that when the XPanel connects, it synchronizes state.

Keeping Organized

But before we go into that, have you noticed we have a few join numbers sprinkled around our program? It’s manageable for now, but what happens when we have hundreds of joins we’re trying to track. Here’s how a lot of SIMPL# programmers stay organized with that: enums. Lets add a couple to our namespace just above our class:

namespace Vc4Test1
{
    public enum SystemJoins
    {
        PowerOn = 10,
        PowerOff = 11,
        PowerToggle = 12,
        PowerTransition = 13
    }

    public enum SystemFb
    {
        PowerOnFb = 10,
        PowerOffFb = 11,
        PowerToggleFb = 12
    }

    public class ControlSystem : CrestronControlSystem
    {

Now we can go into our program and replace those random join numbers with a meaningful name. And the best part, if we have to move our joins around, we just change the value up at the top of the namespace rather than hunt through our entire program. There are a couple places we need to update:

public override void InitializeSystem()
{
    try
    {
        tp1 = new XpanelForSmartGraphics(0x03, this);
        tp1.SigChange += tp_SigChange;
        tp1.BooleanOutput[(uint)SystemJoins.PowerToggle].UserObject = new Action<bool>(press => { if (press) ToggleSystemPower(); });
        tp1.Register();
    }
    catch (Exception e)
    {
        ErrorLog.Error("Error in InitializeSystem: {0}", e.Message);
    }
}
void ToggleSystemPower()
{
    bSystemPowerOn = !bSystemPowerOn;
    tp1.BooleanInput[(uint)SystemFb.PowerOnFb].BoolValue = bSystemPowerOn;
    tp1.BooleanInput[(uint)SystemFb.PowerOffFb].BoolValue = !bSystemPowerOn;
}

Notice that we have to cast our join enums to uint to satisfy the C# compiler. At least now when we glance through this code and see that we’re setting SystemFb.PowerOnFb we can guess what it does versus only seeing the number 10.

Staying in Sync

Now lets handle synchronizing the XPanel state when it connects:

public override void InitializeSystem()
{
    try
    {
        tp1 = new XpanelForSmartGraphics(0x03, this);
                
        tp1.OnlineStatusChange += tp_OnlineChange;
        tp1.UserSpecifiedObject = new Action<bool>(online => { if (online) UpdateFeedback(); });
                
        tp1.SigChange += tp_SigChange;
        tp1.BooleanOutput[(uint)SystemJoins.PowerToggle].UserObject = new Action<bool>(press => { if (press) ToggleSystemPower(); });
        
        tp1.Register();
    }
    catch (Exception e)
    {
        ErrorLog.Error("Error in InitializeSystem: {0}", e.Message);
    }
}

Devices can also have UserObjects attached to them (but they’re named UserSpecifiedObject instead). We follow the same pattern: assign an Action<bool> delegate that will call the UpdateFeedback method when the device comes online. Let’s define that method now:

void UpdateFeedback()
{
    tp1.BooleanInput[(uint)SystemFb.PowerOnFb].BoolValue = bSystemPowerOn;
    tp1.BooleanInput[(uint)SystemFb.PowerOffFb].BoolValue = !bSystemPowerOn;
    tp1.BooleanInput[(uint)SystemFb.PowerToggleFb].BoolValue = bSystemPowerOn;
}

And we need to define the tp_OnlineChange method that will call our delegate:

public void tp_OnlineChange(GenericBase dev, OnlineOfflineEventArgs args)
{
    var obj = dev.UserSpecifiedObject;

    if (obj is Action<bool>)
    {
        var func = (Action<bool>)obj;
        func(args.DeviceOnLine);
    }
}

And lastly, we should update our ToggleSystemPower method to call UpdateFeedback instead:

void ToggleSystemPower()
{
    bSystemPowerOn = !bSystemPowerOn;

    UpdateFeedback();
}

We’re on a roll, but let’s add one more thing…

Finishing Touches

Let’s make sure to send the system state as readable text to the panel AFTER the transition finishes. First we need to add another join to our enum:

public enum SystemJoins
{
    PowerOn = 10,
    PowerOff = 11,
    PowerToggle = 12,
    PowerTransition = 13
}

And then we need to add another callback:

public override void InitializeSystem()
{
    try
    {
        tp1 = new XpanelForSmartGraphics(0x03, this);
                
        tp1.OnlineStatusChange += tp_OnlineChange;
        tp1.UserSpecifiedObject = new Action<bool>(online => { if (online) UpdateFeedback(); });
                
        tp1.SigChange += tp_SigChange;
        tp1.BooleanOutput[(uint)SystemJoins.PowerToggle].UserObject = new Action<bool>(press => { if (press) ToggleSystemPower(); });
        tp1.BooleanOutput[(uint)SystemJoins.PowerTransition].UserObject = new Action<bool>(done => { if (done) UpdatePowerStatusText(); });
                
        tp1.Register();
    }
    catch (Exception e)
    {
        ErrorLog.Error("Error in InitializeSystem: {0}", e.Message);
    }
}

Then create the UpdatePowerStatusText method:

void UpdatePowerStatusText()
{
    if (bSystemPowerOn)
        tp1.StringInput[10].StringValue = "ON";
    else
        tp1.StringInput[10].StringValue = "OFF";
}

Build the program, upload it to the VC-4 server, recreate your room and start it up. Now when the power feedback transitions, you’ll see the new state update on the panel. Not much visual difference from the last stage, but under the hood we’ve done a few changes to make things easier for us later.

As always, you can check out this code on my GitHub.

2 thoughts on “VC-4: Part 3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s