def ProcessManualOptionsKey(keyValue):

    # Move to manual options select mode and display keyboard.
    GD.currentMode = GD.MODE_MANUAL_OPTIONS
    display.DisplayKeyboardImage(useMode=GD.currentMode)

    # We have displayed a select keyboard so we need to set the select keys text idle and clear any bands.
    keyData.UpdateSelectKeyGroupText(textIdle=GD.KEY_GROUP_MANUAL_MODE)
    keyData.UpdateSelectKeyGroupBand(bandNone=(GD.KEY_GROUP_MANUAL_MODE))

    # Clear any previous band on manual control key and select keys on the following menu.
    keyData.SetDefaultKeyImage(GD.KEYVALUE_MANUAL_OVERRIDE)
    keyData.UpdateSelectKeyGroupText(
        textIdle=GD.KEY_GROUP_MANUAL_CONTROL_SELECT)
    keyData.UpdateSelectKeyGroupBand(
        bandNone=(GD.KEY_GROUP_MANUAL_CONTROL_SELECT))

    # We will check if an override is active for any manual controls. If it is we will set the manual control key and the select key
    # on the following menu to flash (yellow band). We will move to manual options disabled mode so the user cannot select a
    # manual option except manual control.

    # Get each manual control group.
    for group in range(0, len(GD.ALL_MANUAL_OVERRIDE_GROUPS)):
        # Scan each group.
        for controlBit in GD.ALL_MANUAL_OVERRIDE_GROUPS[group]:
            # If the override bit is active set band flashing on manual control key and the select key on following menu.
            if system.systemControl[controlBit].CheckIfOverrideActive(
            ) == True:
                keyData.SetKeyBand1Flashing(GD.KEYVALUE_MANUAL_OVERRIDE)
                keyData.SetKeyBand1Flashing(
                    GD.KEY_GROUP_MANUAL_CONTROL_SELECT[group])
                # If this is a manual control for tank 1, tank 2 or the boiler then disable manual options
                if controlBit in (GD.DISABLED_MANUAL_OVERRIDE_GROUPS):
                    GD.currentMode = GD.MODE_MANUAL_OPTIONS_DISABLED

    # If we are NOT disabled read the config bits and update the bands on the control keys. There are 2 groups of keys: the heating
    # control keys and the boiloer control keys.
    if GD.currentMode == GD.MODE_MANUAL_OPTIONS:

        keyData.SetControlBandStatus(GD.HEATING_MANUAL_CONTROL_GROUP,
                                     GD.KEY_GROUP_HEATING_MODE)
        keyData.SetControlBandStatus(GD.BOILER_MANUAL_CONTROL_GROUP,
                                     GD.KEY_GROUP_BOILER_MODE)

        # Display all the control keys with their new band status.
        display.UpdateSelectKeyImages(GD.KEY_GROUP_MANUAL_MODE, GD.UPDATE_ALL)

        # Tell user they can select an option.
        userPrompt = GD.MANUAL_OPTIONS_PROMPT

    else:

        # Tell user options not available
        userPrompt = GD.OPTIONS_DISABLED_PROMPT

    # Display new prompt to user.
    display.DisplayMiddleLeftInfoPrompt(userPrompt)

    return 1
def ProcessManualOverrideKeySubMenu(keyValue):

    # Keep a list of parameters for each manual control key.
    parameters = {
        GD.KEYVALUE_IMMERSION_CONTROL:
        (GD.MODE_IMMERSION_MANUAL_CONTROL, GD.IMMERSION_MANUAL_OVERRIDE_GROUP,
         GD.KEY_GROUP_ALL_IMM, GD.IMMERSION_SELECT_PROMPT),
        GD.KEYVALUE_WOODBURNER_CONTROL:
        (GD.MODE_WOODBURNER_MANUAL_CONTROL,
         GD.WOODBURNER_MANUAL_OVERRIDE_GROUP, GD.KEY_GROUP_ALL_WB,
         GD.WB_PUMP_SELECT_PROMPT),
        GD.KEYVALUE_TANK_1_CONTROL:
        (GD.MODE_TANK_1_MANUAL_CONTROL, GD.TANK_1_MANUAL_OVERRIDE_GROUP,
         GD.KEY_GROUP_ALL_T1, GD.TANK_1_CONTROL_PROMPT),
        GD.KEYVALUE_TANK_2_CONTROL:
        (GD.MODE_TANK_2_MANUAL_CONTROL, GD.TANK_2_MANUAL_OVERRIDE_GROUP,
         GD.KEY_GROUP_ALL_T2, GD.TANK_2_CONTROL_PROMPT),
        GD.KEYVALUE_BOILER_CONTROL:
        (GD.MODE_BOILER_MANUAL_CONTROL, GD.BOILER_MANUAL_OVERRIDE_GROUP,
         GD.KEY_GROUP_ALL_BOILER, GD.BOILER_CONTROL_PROMPT),
        GD.KEYVALUE_HEATING_CONTROL:
        (GD.MODE_HEATING_MANUAL_CONTROL, GD.HEATING_MANUAL_OVERRIDE_GROUP,
         GD.KEY_GROUP_ALL_HEATING, GD.HEATING_CONTROL_PROMPT)
    }

    if keyValue in parameters:

        # Get parameters for this manual control select key.
        mode, control, keyGroup, prompt = parameters[keyValue]

        # The onkeys are the 1st half and the offkeys are the 2nd half of the keygroup list.
        onKeys = keyGroup[0:len(keyGroup) / 2]
        offKeys = keyGroup[len(keyGroup) / 2:len(keyGroup)]

        # Move to the new mode and display keyboard.
        GD.currentMode = mode
        display.DisplayKeyboardImage(useMode=GD.currentMode)

        # Set the control key bands according to the system configuration data bits.
        keyData.SetControlBandStatus(control, onKeys)
        keyData.SetControlBandStatus(control, offKeys, checkIfHigh=False)

        # Display the updated key images.
        display.UpdateSelectKeyImages(keyGroup, GD.UPDATE_ALL)

        # Prompt user for action.
        display.DisplayMiddleLeftInfoPrompt(prompt)

    return 1
def ProcessSystemKey(zone):

    # Scan through the system 'mode' keys to find which mode should be active.
    for systemKey in GD.KEY_GROUP_SYSTEM_MODE:
        systemBit = GD.KEY_TO_CONTROL_BIT_LOOKUP[systemKey]
        if system.systemControl[systemBit].CheckIfBitHigh() == True:
            # Exit now we have found the active mode.
            break

    # Move to required mode.
    GD.currentMode = GD.KEY_TO_MODE_LOOKUP[systemKey]

    # Display keyboard for this mode
    display.DisplayKeyboardImage(useMode=GD.currentMode)

    # Read the config bits and update the bands on the control keys.
    keyData.SetControlBandStatus(GD.SYSTEM_CONTROL_GROUP,
                                 GD.KEY_GROUP_SYSTEM_MODE)

    # Display all the control keys with their new band status.
    display.UpdateSelectKeyImages(GD.KEY_GROUP_SYSTEM_MODE, GD.UPDATE_ALL)

    # Display user prompt.
    display.DisplayMiddleLeftInfoPrompt(GD.SYSTEM_SELECT_PROMPT)

    return 1
def ProcessOilOffKey(keyValue):

    # Do not process if we are disabled.
    if GD.currentMode == GD.MODE_MANUAL_OPTIONS_DISABLED: return 1

    # If oil to heating is active we need to make it idle and set T1 to heating. Set T1 to heating key text active.
    # Note this test must be done first before we change any config bits.
    if (system.systemControl[
            GD.SYSTEM_MANUAL_OIL_BOILER_TO_HEATING].CheckIfBitHigh() == True):

        system.UpdateSystemControlBits(
            bitsHigh=GD.SYSTEM_MANUAL_TANK_1_TO_HEATING,
            bitsLow=GD.HEATING_MANUAL_CONTROL_GROUP)
        keyData.UpdateSelectKeyGroupText(textActive=GD.KEYVALUE_T1_TO_HEAT,
                                         textIdle=GD.KEY_GROUP_HEATING_MODE)

    # Set the Oil boiler off config bit and make boiler off key text active.
    system.UpdateSystemControlBits(bitsHigh=GD.SYSTEM_MANUAL_OIL_BOILER_OFF,
                                   bitsLow=GD.BOILER_MANUAL_CONTROL_GROUP)
    keyData.UpdateSelectKeyGroupText(textActive=GD.KEYVALUE_OIL_OFF,
                                     textIdle=GD.KEY_GROUP_BOILER_MODE)

    # Read the config bits and update the bands on all the manual option control keys.
    keyData.SetControlBandStatus(GD.ALL_MANUAL_CONTROL_GROUP,
                                 GD.KEY_GROUP_MANUAL_MODE)

    # Display all the control keys with their new band status.
    display.UpdateSelectKeyImages(GD.KEY_GROUP_MANUAL_MODE, GD.UPDATE_ALL)

    return 1
def ProcessSystemModeKeys(keyValue):

    # Move to required mode.
    GD.currentMode = GD.KEY_TO_MODE_LOOKUP[keyValue]

    # Display keyboard for this mode
    display.DisplayKeyboardImage(useMode=GD.currentMode)

    # Get config bit for this mode.
    systemBit = GD.KEY_TO_CONTROL_BIT_LOOKUP[keyValue]

    # Set the config bit and clear the other config bits.
    system.UpdateSystemControlBits(bitsHigh=systemBit,
                                   bitsLow=GD.SYSTEM_CONTROL_GROUP)

    # Make key text active and clear other mode keys.
    keyData.UpdateSelectKeyGroupText(textActive=keyValue,
                                     textIdle=GD.KEY_GROUP_SYSTEM_MODE)

    # Now read the config bits and update the bands on all the system control keys.
    keyData.SetControlBandStatus(GD.SYSTEM_CONTROL_GROUP,
                                 GD.KEY_GROUP_SYSTEM_MODE)

    # Display all the control keys with their new band status.
    display.UpdateSelectKeyImages(GD.KEY_GROUP_SYSTEM_MODE, GD.UPDATE_ALL)

    # Update all the zone statuses. We do this so that the zone on/off bands will show which zones will be turning on when we
    # have switched from off mode to one of the active modes (man, auto or holiday).
    for zone in range(0, 30):
        zones.UpdateZoneStatus(zone)

    return 1
def ProcessOilToHeatingKey(keyValue):

    # Do not process if we are disabled.
    if GD.currentMode == GD.MODE_MANUAL_OPTIONS_DISABLED: return 1

    # Set the Oil to heating config bit and make Oil to heating key text active.
    system.UpdateSystemControlBits(
        bitsHigh=GD.SYSTEM_MANUAL_OIL_BOILER_TO_HEATING,
        bitsLow=GD.ALL_MANUAL_CONTROL_GROUP)
    keyData.UpdateSelectKeyGroupText(textActive=GD.KEYVALUE_OIL_TO_HEAT,
                                     textIdle=GD.KEY_GROUP_MANUAL_MODE)

    # Read the config bits and update the bands on all the manual option control keys.
    keyData.SetControlBandStatus(GD.ALL_MANUAL_CONTROL_GROUP,
                                 GD.KEY_GROUP_MANUAL_MODE)

    # Display all the control keys with their new band status.
    display.UpdateSelectKeyImages(GD.KEY_GROUP_MANUAL_MODE, GD.UPDATE_ALL)

    return 1
def ProcessManualOverrideOnOffKey(keyValue):

    # This is a lookup dictionary of tuples for parameters for the key we are processing. For each key we keep the following values:
    # (0) The keyvalue for the opposite key - if this is an on key this value would be the off key.
    # (1) The system control bit this key controls.
    # (2) The system control bit for the opposite control. This is none for for an on/off key as there is no opposite control bit.
    # (3) An index into a 2nd lookup table that holds values for the group this key is in.
    keyParameters = {

        # keyValue: (opposite key (0), system bit for this key (1), system bit for opposite key (2), index to group parameter (3)).
        # Immersion control.
        GD.KEYVALUE_IMM_1_ON: (GD.KEYVALUE_IMM_1_OFF, GD.SYSTEM_IMM_1,
                               GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_2_ON: (GD.KEYVALUE_IMM_2_OFF, GD.SYSTEM_IMM_2,
                               GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_3_ON: (GD.KEYVALUE_IMM_3_OFF, GD.SYSTEM_IMM_3,
                               GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_4_ON: (GD.KEYVALUE_IMM_4_OFF, GD.SYSTEM_IMM_4,
                               GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_1_OFF: (GD.KEYVALUE_IMM_1_ON, GD.SYSTEM_IMM_1,
                                GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_2_OFF: (GD.KEYVALUE_IMM_2_ON, GD.SYSTEM_IMM_2,
                                GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_3_OFF: (GD.KEYVALUE_IMM_3_ON, GD.SYSTEM_IMM_3,
                                GD.SYSTEM_NONE, 0),
        GD.KEYVALUE_IMM_4_OFF: (GD.KEYVALUE_IMM_4_ON, GD.SYSTEM_IMM_4,
                                GD.SYSTEM_NONE, 0),

        # Woodburner control.
        GD.KEYVALUE_WB_PUMP_1_ON:
        (GD.KEYVALUE_WB_PUMP_1_OFF, GD.SYSTEM_WOODBURNER_PUMP_1,
         GD.SYSTEM_NONE, 1),
        GD.KEYVALUE_WB_PUMP_2_ON:
        (GD.KEYVALUE_WB_PUMP_2_OFF, GD.SYSTEM_WOODBURNER_PUMP_2,
         GD.SYSTEM_NONE, 1),
        GD.KEYVALUE_WB_PUMP_1_OFF:
        (GD.KEYVALUE_WB_PUMP_1_ON, GD.SYSTEM_WOODBURNER_PUMP_1, GD.SYSTEM_NONE,
         1),
        GD.KEYVALUE_WB_PUMP_2_OFF:
        (GD.KEYVALUE_WB_PUMP_2_ON, GD.SYSTEM_WOODBURNER_PUMP_2, GD.SYSTEM_NONE,
         1),

        # Tank 1 control.
        GD.KEYVALUE_TANK_1_PUMP_ON: (GD.KEYVALUE_TANK_1_PUMP_OFF,
                                     GD.SYSTEM_TANK_1_PUMP, GD.SYSTEM_NONE, 2),
        GD.KEYVALUE_V1_EXT_TO_T1:
        (GD.KEYVALUE_V1_EXT_TO_HEATING, GD.SYSTEM_V1_EXT_TO_TANK_1,
         GD.SYSTEM_V1_EXT_TO_HEATING, 2),
        GD.KEYVALUE_TANK_1_PUMP_OFF:
        (GD.KEYVALUE_TANK_1_PUMP_ON, GD.SYSTEM_TANK_1_PUMP, GD.SYSTEM_NONE, 2),
        GD.KEYVALUE_V1_EXT_TO_HEATING: (GD.KEYVALUE_V1_EXT_TO_T1,
                                        GD.SYSTEM_V1_EXT_TO_TANK_1,
                                        GD.SYSTEM_V1_EXT_TO_HEATING, 2),

        # Tank 2 control.
        GD.KEYVALUE_TANK_2_PUMP_ON: (GD.KEYVALUE_TANK_2_PUMP_OFF,
                                     GD.SYSTEM_TANK_2_PUMP, GD.SYSTEM_NONE, 3),
        GD.KEYVALUE_V2_T2_TO_INT: (GD.KEYVALUE_V2_T2_RECYCLE,
                                   GD.SYSTEM_EXT_TO_INT, GD.SYSTEM_NONE, 3),
        GD.KEYVALUE_TANK_2_PUMP_OFF:
        (GD.KEYVALUE_TANK_2_PUMP_ON, GD.SYSTEM_TANK_2_PUMP, GD.SYSTEM_NONE, 3),
        GD.KEYVALUE_V2_T2_RECYCLE: (GD.KEYVALUE_V2_T2_TO_INT,
                                    GD.SYSTEM_EXT_TO_INT, GD.SYSTEM_NONE, 3),

        # Boiler control.
        GD.KEYVALUE_BOILER_ON: (GD.KEYVALUE_BOILER_OFF, GD.SYSTEM_BOILER_ON,
                                GD.SYSTEM_NONE, 4),
        GD.KEYVALUE_V3_BOILER_TO_INT: (GD.KEYVALUE_V3_BOILER_TO_T2,
                                       GD.SYSTEM_V3_BOILER_TO_INT,
                                       GD.SYSTEM_NONE, 4),
        GD.KEYVALUE_BOILER_OFF: (GD.KEYVALUE_BOILER_ON, GD.SYSTEM_BOILER_ON,
                                 GD.SYSTEM_NONE, 4),
        GD.KEYVALUE_V3_BOILER_TO_T2: (GD.KEYVALUE_V3_BOILER_TO_INT,
                                      GD.SYSTEM_V3_BOILER_TO_INT,
                                      GD.SYSTEM_NONE, 4),

        # Heating control.
        GD.KEYVALUE_RAD_PUMP_ON: (GD.KEYVALUE_RAD_PUMP_OFF, GD.SYSTEM_RAD_PUMP,
                                  GD.SYSTEM_NONE, 5),
        GD.KEYVALUE_UFH_PUMP_ON: (GD.KEYVALUE_UFH_PUMP_OFF, GD.SYSTEM_UFH_PUMP,
                                  GD.SYSTEM_NONE, 5),
        GD.KEYVALUE_RAD_PUMP_OFF: (GD.KEYVALUE_RAD_PUMP_ON, GD.SYSTEM_RAD_PUMP,
                                   GD.SYSTEM_NONE, 5),
        GD.KEYVALUE_UFH_PUMP_OFF: (GD.KEYVALUE_UFH_PUMP_ON, GD.SYSTEM_UFH_PUMP,
                                   GD.SYSTEM_NONE, 5)
    }

    # Lookup tuple of tuples for group parameters that a key is in. We keep the following values:
    # (0) The key group that this key is in.
    # (1) The control group that the control bit for this key is in.
    # (3) The control key in the keyboard that selected the current keyboard. This enables us to set the override band for this key.
    groupParameters = (

        # key group (0), control group (1), control key (2)
        (GD.KEY_GROUP_ALL_IMM, GD.IMMERSION_MANUAL_OVERRIDE_GROUP,
         GD.KEYVALUE_IMMERSION_CONTROL),
        (GD.KEY_GROUP_ALL_WB, GD.WOODBURNER_MANUAL_OVERRIDE_GROUP,
         GD.KEYVALUE_WOODBURNER_CONTROL),
        (GD.KEY_GROUP_ALL_T1, GD.TANK_1_MANUAL_OVERRIDE_GROUP,
         GD.KEYVALUE_TANK_1_CONTROL),
        (GD.KEY_GROUP_ALL_T2, GD.TANK_2_MANUAL_OVERRIDE_GROUP,
         GD.KEYVALUE_TANK_2_CONTROL),
        (GD.KEY_GROUP_ALL_BOILER, GD.BOILER_MANUAL_OVERRIDE_GROUP,
         GD.KEYVALUE_BOILER_CONTROL),
        (GD.KEY_GROUP_ALL_HEATING, GD.HEATING_MANUAL_OVERRIDE_GROUP,
         GD.KEYVALUE_HEATING_CONTROL))

    if keyValue in keyParameters:

        # Get the opposite key, control bit and group index for this key.
        oppositeKey, controlBit, oppositeControlBit, groupIndex = keyParameters[
            keyValue][0:4]

        # Get all the keys, control bits and the menu control key for the group this key is in.
        keyGroup, controlGroup, controlKey = groupParameters[groupIndex][0:3]

        # The onkeys are the 1st half and the offkeys are the 2nd half of the keygroup list.
        onKeys = keyGroup[0:len(keyGroup) / 2]
        offKeys = keyGroup[len(keyGroup) / 2:len(keyGroup)]

        # Clear any active override indication on the opposite key.
        keyData.UpdateSelectKeyGroupText(GD.KEYVALUE_NONE, oppositeKey)

        # Are we doing an on or off operation?
        if keyValue in (onKeys):
            # Attempt to set bit high. If bit is in override low this will cancel the override. result will be true if we do set bit override high.
            result = system.systemControl[controlBit].SetOutputOverrideBitHigh(
            )
        else:
            # Attempt to set bit low. If bit is in override high this will cancel the override. result will be true if we do set bit override low.
            result = system.systemControl[controlBit].SetOutputOverrideBitLow()

        # If we have an opposite bit we need to set opposite level as bits are exclusive.
        if oppositeControlBit != GD.SYSTEM_NONE:
            if system.systemControl[controlBit].CheckIfBitHigh() == True:
                system.systemControl[oppositeControlBit].SetOutputBitLow()
            else:
                system.systemControl[oppositeControlBit].SetOutputBitHigh()

        # If we did a high or low operation make text active. An override cancel will return false.
        if result == True:
            keyData.UpdateSelectKeyGroupText(keyValue)

        # We will check if any override is active for this group. If it is we will set the control key for the group to flash (yellow band).
        keyData.SetKeyNoBand(controlKey)
        for controlBit in controlGroup:
            if system.systemControl[controlBit].CheckIfOverrideActive(
            ) == True:
                keyData.SetKeyBand1Flashing(controlKey)

        # Set the control key bands according to the system configuration data bits.
        keyData.SetControlBandStatus(controlGroup, onKeys)
        keyData.SetControlBandStatus(controlGroup, offKeys, False)

        # Display the updated key images.
        display.UpdateSelectKeyImages(keyGroup, GD.UPDATE_ALL)

    return 1