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 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 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 ProcessStatusKey(keyValue):

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

    # Save the index for the 1st status so that we know which status is currently displayed.
    system.systemControl[GD.SYSTEM_NONE].SaveStatusIndex(1)

    # Display the 1st status. The number of statuses available is returned so we can check if there are more statuses to display
    # and set the 'Next' key on if there are.
    numberOfStatus = display.DisplayStatus(keyValue, 1)

    # Clear the 'previous key'.
    display.DisplayKeyImageSequence(GD.KEYVALUE_PREV_STATUS_ENTRY,
                                    GD.KEY_IMAGE_BLANK)

    # If there is more than 1 status display the 'next' key.
    if numberOfStatus > 1:
        display.DisplayKeyImageSequence(GD.KEYVALUE_NEXT_STATUS_ENTRY,
                                        GD.KEY_IMAGE_NEXT)
    else:
        display.DisplayKeyImageSequence(GD.KEYVALUE_NEXT_STATUS_ENTRY,
                                        GD.KEY_IMAGE_BLANK)

    return 1
def ProcessUfhSelectKey(keyValue):

    # We have a zone selected so move to ufh select mode, keyboard and refresh select keys if we are not already there.
    if GD.currentMode != GD.MODE_UFH_ZONE_SELECT:
        GD.currentMode = GD.MODE_UFH_ZONE_SELECT
        display.DisplayKeyboardImage(useMode=GD.currentMode)
        display.UpdateSelectKeyImages(GD.KEY_GROUP_UFH)

    # Set ufh select key active.
    keyData.UpdateSelectKeyGroupText(keyValue, GD.KEY_GROUP_UFH)
    display.UpdateSelectKeyImages(GD.KEY_GROUP_UFH, GD.UPDATE_CHANGED)

    return 1
def ProcessImmersionTimesKey(keyValue):

    # Move to immersion times select mode and display keyboard.
    GD.currentMode = GD.MODE_IMMERSION_WAITING_SELECT
    display.DisplayKeyboardImage(useMode=GD.currentMode)

    # Clear any previously active select key and display any active bands.
    keyData.UpdateSelectKeyGroupText(textIdle=GD.KEY_GROUP_IMMERSIONS)
    display.UpdateSelectKeyImages(GD.KEY_GROUP_IMMERSIONS)

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

    return 1
def ProcessUfhSelectExitKey(keyValue):

    # Return to ufh waiting select mode and keyboard.
    GD.currentMode = GD.MODE_UFH_WAITING_ZONE_SELECT
    display.DisplayKeyboardImage(useMode=GD.currentMode)

    # Clear any previously active select key and display any active bands.
    keyData.UpdateSelectKeyGroupText(textIdle=GD.KEY_GROUP_UFH)
    display.UpdateSelectKeyImages(GD.KEY_GROUP_UFH)

    # Update prompts.
    display.DisplayMiddleLeftInfoPrompt(GD.UFH_SELECT_PROMPT)
    display.DisplayBottomLeftInfoPrompt(GD.INFO_1_BLANKED)
    display.DisplayZoneMode()

    return 1
def ProcessRadKey(zone):

    # Move to rad waiting mode and display keyboard.
    GD.currentMode = GD.MODE_RAD_WAITING_ZONE_SELECT
    display.DisplayKeyboardImage(useMode=GD.currentMode)

    # Set rad key active.
    # keyData.UpdateSelectKeyGroupText (GD.KEYVALUE_RAD, GD.KEY_GROUP_WAITING_MODE)
    # display.UpdateSelectKeyImages (GD.KEY_GROUP_WAITING_MODE, GD.UPDATE_CHANGED)

    # Clear any previously active select key and display any active bands.
    keyData.UpdateSelectKeyGroupText(textIdle=GD.KEY_GROUP_RADS)
    display.UpdateSelectKeyImages(GD.KEY_GROUP_RADS)

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

    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 ProcessUfhKey(zone):

    # Only process if we are not already in ufh waiting mode.
    if GD.currentMode != GD.MODE_UFH_WAITING_ZONE_SELECT:

        # Move to ufh waiting mode and display keyboard.
        GD.currentMode = GD.MODE_UFH_WAITING_ZONE_SELECT
        display.DisplayKeyboardImage(useMode=GD.currentMode)

        # Set ufh key active.
        #keyData.UpdateSelectKeyGroupText (GD.KEYVALUE_UFH, GD.KEY_GROUP_WAITING_MODE)
        # display.UpdateSelectKeyImages (GD.KEY_GROUP_WAITING_MODE, GD.UPDATE_CHANGED)

        # Clear any previously active select key and display any active bands.
        keyData.UpdateSelectKeyGroupText(textIdle=GD.KEY_GROUP_UFH)
        display.UpdateSelectKeyImages(GD.KEY_GROUP_UFH)

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

    return 1
def ProcessImmersionSelectKey(keyValue):

    # Check if we are in override. If we are; move back to waiting select and warn user no operation allowed.
    if system.systemControl[GD.KEY_TO_CONTROL_BIT_LOOKUP[
            keyValue]].CheckIfOverrideActive() == True:
        GD.currentMode = GD.MODE_IMMERSION_WAITING_SELECT
        display.DisplayKeyboardImage(useMode=GD.currentMode)
        display.DisplayMiddleLeftInfoPrompt(GD.OPTIONS_DISABLED_PROMPT)

    else:
        # We have a zone selected so move to immersion select mode, keyboard and refresh select keys if we are not already there.
        if GD.currentMode != GD.MODE_IMMERSION_SELECT:
            GD.currentMode = GD.MODE_IMMERSION_SELECT
            display.DisplayKeyboardImage(useMode=GD.currentMode)
            display.UpdateSelectKeyImages(GD.KEY_GROUP_IMMERSIONS)

    # Set the zone select key active.
    keyData.UpdateSelectKeyGroupText(keyValue, GD.KEY_GROUP_IMMERSIONS)
    display.UpdateSelectKeyImages(GD.KEY_GROUP_IMMERSIONS, GD.UPDATE_CHANGED)

    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