<commit_before>import logging
import struct
import copy

# ZigBee Addressing
BROADCAST_LONG = b'\x00\x00\x00\x00\x00\x00\xff\xff' 
BROADCAST_SHORT = b'\xff\xfd'

# ZigBee Profile IDs
PROFILE_ID_ZDP     = b'\x00\x00'  # ZigBee Device Profile
PROFILE_ID_HA      = b'\x01\x04'  # HA Device Profile
PROFILE_ID_LL      = b'\xc0\x5e'  # Light Link Profile
PROFILE_ID_ALERTME = b'\xc2\x16'  # AlertMe Private Profile

# ZigBee Endpoints
ENDPOINT_ZDO       = b'\x00'      # ZigBee Device Objects Endpoint
ENDPOINT_ALERTME   = b'\x02'      # AlertMe / Iris Endpoint

# ZDP Status
ZDP_STATUS_OK         = b'\x00'
ZDP_STATUS_INVALID    = b'\x80'
ZDP_STATUS_NOT_FOUND  = b'\x81'

# ZDO Clusters
CLUSTER_ID_ZDO_NETWORK_ADDRESS_REQ   = b'\x00\x00'   # Network (16-bit) Address Request
CLUSTER_ID_ZDO_NETWORK_ADDRESS_RESP  = b'\x80\x00'   # Network (16-bit) Address Response
CLUSTER_ID_ZDO_NODE_DESCRIPTOR_RESP  = b'\x802'      # Node Descriptor Response
CLUSTER_ID_ZDO_SIMPLE_DESCRIPTOR_REQ = b'\x00\x04'   # Simple Descriptor Request
CLUSTER_ID_ZDO_ACTIVE_ENDPOINTS_REQ  = b'\x00\x05'   # Active Endpoints Request
CLUSTER_ID_ZDO_ACTIVE_ENDPOINTS_RESP = b'\x80\x05'   # Active Endpoints Response
CLUSTER_ID_ZDO_MATCH_DESCRIPTOR_REQ  = b'\x00\x06'   # Match Descriptor Request
CLUSTER_ID_ZDO_MATCH_DESCRIPTOR_RESP = b'\x80\x06'   # Match Descriptor Response
CLUSTER_ID_ZDO_DEVICE_ANNOUNCE       = b'\x00\x13'   # Device Announce Message
CLUSTER_ID_ZDO_MGNT_ROUTING_REQ      = b'\x00\x32'   # Management Routing Request
CLUSTER_ID_ZDO_PERMIT_JOIN_REQ       = b'\x00\x36'   # Permit Join Request
CLUSTER_ID_ZDO_MGNT_NETWORK_UPDATE   = b'\x80\x38'   # Management Network Update Notify

# AlertMe Clusters
CLUSTER_ID_AM_SWITCH    = b'\x00\xee'
CLUSTER_ID_AM_POWER     = b'\x00\xef'
CLUSTER_ID_AM_STATUS    = b'\x00\xf0'
CLUSTER_ID_AM_TAMPER    = b'\x00\xf2'
CLUSTER_ID_AM_BUTTON    = b'\x00\xf3'
CLUSTER_ID_AM_DISCOVERY = b'\x00\xf6'
CLUSTER_ID_AM_SECURITY  = b'\x05\x00'

# AlertMe Cluster Commands
CLUSTER_CMD_AM_SECURITY        = b'\x00'  # Security Event (Sensors)
CLUSTER_CMD_AM_STATE_REQ       = b'\x01'  # State Request (SmartPlug)
CLUSTER_CMD_AM_STATE_CHANGE    = b'\x02'  # Change State (SmartPlug)
CLUSTER_CMD_AM_STATE_RESP      = b'\x80'  # Switch Status Update
CLUSTER_CMD_AM_PWR_DEMAND      = b'\x81'  # Power Demand Update
CLUSTER_CMD_AM_PWR_CONSUMPTION = b'\x82'  # Power Consumption & Uptime Update
CLUSTER_CMD_AM_PWR_UNKNOWN     = b'\x86'  # Unknown British Gas Power Meter Update
CLUSTER_CMD_AM_MODE_REQ        = b'\xfa'  # Mode Change Request
CLUSTER_CMD_AM_STATUS          = b'\xfb'  # Status Update
CLUSTER_CMD_AM_VERSION_REQ     = b'\xfc'  # Version Information Request
CLUSTER_CMD_AM_RSSI            = b'\xfd'  # RSSI Range Test Update
CLUSTER_CMD_AM_VERSION_RESP    = b'\xfe'  # Version Information Response

# At the moment I am not sure what/if the following dictionary will be used?
# It is here to describe the relationship between Cluster ID and Cmd.
# One day this dict may be used by the process_message() function and link with the parse_xxxxx() functions?
alertme_cluster_cmds = {
    CLUSTER_ID_AM_SWITCH: {
        CLUSTER_CMD_AM_STATE_REQ: "Relay State Request (SmartPlug)",
        CLUSTER_CMD_AM_STATE_CHANGE: "Relay State Change (SmartPlug)",
        CLUSTER_CMD_AM_STATE_RESP: "Switch Status Update"
    },
    CLUSTER_ID_AM_POWER: {
        CLUSTER_CMD_AM_PWR_DEMAND: "Power Demand Update",
        CLUSTER_CMD_AM_PWR_CONSUMPTION: "Power Consumption & Uptime Update",
        CLUSTER_CMD_AM_PWR_UNKNOWN: "Unknown British Gas Power Meter Update"
    },
    CLUSTER_ID_AM_STATUS: {
        CLUSTER_CMD_AM_MODE_REQ: "Mode Change Request",
        CLUSTER_CMD_AM_STATUS: "Status Update"
    },
    CLUSTER_ID_AM_TAMPER: {},
    CLUSTER_ID_AM_BUTTON: {},
    CLUSTER_ID_AM_DISCOVERY: {
        CLUSTER_CMD_AM_RSSI: "RSSI Range Test Update",
        CLUSTER_CMD_AM_VERSION_REQ: "Version Information Request",
        CLUSTER_CMD_AM_VERSION_RESP: "Version Information Response"
    },
    CLUSTER_ID_AM_SECURITY: {
        CLUSTER_CMD_AM_SECURITY: "Security Command"
    }
}

messages = {
    'version_info_request': {
        'name': 'Version Info Request',
        'frame': {
            'profile': PROFILE_ID_ALERTME,
            'cluster': CLUSTER_ID_AM_DISCOVERY,
            'src_endpoint': ENDPOINT_ALERTME,
            'dest_endpoint': ENDPOINT_ALERTME,
            'data': lambda params: generate_version_info_request(params)
        }
    },
    'version_info_update': {
        'name': 'Version Info Update',
        'frame': {
            'profile': PROFILE_ID_ALERTME,
            'cluster': CLUSTER_ID_AM_DISCOVERY,
            'src_endpoint': ENDPOINT_ALERTME,
            'dest_endpoint': ENDPOINT_ALERTME,
            'data': lambda params: generate_version_info_update(params)<commit_msg>Adding documentation.<commit_after>import logging
import struct
import copy

# ZigBee Addressing
BROADCAST_LONG = b'\x00\x00\x00\x00\x00\x00\xff\xff' 
BROADCAST_SHORT = b'\xff\xfd'

# ZigBee Profile IDs
PROFILE_ID_ZDP     = b'\x00\x00'  # ZigBee Device Profile
PROFILE_ID_HA      = b'\x01\x04'  # HA Device Profile
PROFILE_ID_LL      = b'\xc0\x5e'  # Light Link Profile
PROFILE_ID_ALERTME = b'\xc2\x16'  # AlertMe Private Profile

# ZigBee Endpoints
ENDPOINT_ZDO       = b'\x00'      # ZigBee Device Objects Endpoint
ENDPOINT_ALERTME   = b'\x02'      # AlertMe / Iris Endpoint

# ZDP Status
ZDP_STATUS_OK         = b'\x00'
ZDP_STATUS_INVALID    = b'\x80'
ZDP_STATUS_NOT_FOUND  = b'\x81'

# ZDO Clusters
CLUSTER_ID_ZDO_NETWORK_ADDRESS_REQ   = b'\x00\x00'   # Network (16-bit) Address Request
CLUSTER_ID_ZDO_NETWORK_ADDRESS_RESP  = b'\x80\x00'   # Network (16-bit) Address Response
CLUSTER_ID_ZDO_NODE_DESCRIPTOR_RESP  = b'\x802'      # Node Descriptor Response
CLUSTER_ID_ZDO_SIMPLE_DESCRIPTOR_REQ = b'\x00\x04'   # Simple Descriptor Request
CLUSTER_ID_ZDO_ACTIVE_ENDPOINTS_REQ  = b'\x00\x05'   # Active Endpoints Request
CLUSTER_ID_ZDO_ACTIVE_ENDPOINTS_RESP = b'\x80\x05'   # Active Endpoints Response
CLUSTER_ID_ZDO_MATCH_DESCRIPTOR_REQ  = b'\x00\x06'   # Match Descriptor Request
CLUSTER_ID_ZDO_MATCH_DESCRIPTOR_RESP = b'\x80\x06'   # Match Descriptor Response
CLUSTER_ID_ZDO_DEVICE_ANNOUNCE       = b'\x00\x13'   # Device Announce Message
CLUSTER_ID_ZDO_MGNT_ROUTING_REQ      = b'\x00\x32'   # Management Routing Request
CLUSTER_ID_ZDO_PERMIT_JOIN_REQ       = b'\x00\x36'   # Permit Join Request
CLUSTER_ID_ZDO_MGNT_NETWORK_UPDATE   = b'\x80\x38'   # Management Network Update Notify

# AlertMe Clusters
CLUSTER_ID_AM_SWITCH    = b'\x00\xee'
CLUSTER_ID_AM_POWER     = b'\x00\xef'
CLUSTER_ID_AM_STATUS    = b'\x00\xf0'
CLUSTER_ID_AM_TAMPER    = b'\x00\xf2'
CLUSTER_ID_AM_BUTTON    = b'\x00\xf3'
CLUSTER_ID_AM_DISCOVERY = b'\x00\xf6'
CLUSTER_ID_AM_SECURITY  = b'\x05\x00'

# AlertMe Cluster Commands
CLUSTER_CMD_AM_SECURITY        = b'\x00'  # Security Event (Sensors)
CLUSTER_CMD_AM_STATE_REQ       = b'\x01'  # State Request (SmartPlug)
CLUSTER_CMD_AM_STATE_CHANGE    = b'\x02'  # Change State (SmartPlug)
CLUSTER_CMD_AM_STATE_RESP      = b'\x80'  # Switch Status Update
CLUSTER_CMD_AM_PWR_DEMAND      = b'\x81'  # Power Demand Update
CLUSTER_CMD_AM_PWR_CONSUMPTION = b'\x82'  # Power Consumption & Uptime Update
CLUSTER_CMD_AM_PWR_UNKNOWN     = b'\x86'  # Unknown British Gas Power Meter Update
CLUSTER_CMD_AM_MODE_REQ        = b'\xfa'  # Mode Change Request
CLUSTER_CMD_AM_STATUS          = b'\xfb'  # Status Update
CLUSTER_CMD_AM_VERSION_REQ     = b'\xfc'  # Version Information Request
CLUSTER_CMD_AM_RSSI            = b'\xfd'  # RSSI Range Test Update
CLUSTER_CMD_AM_VERSION_RESP    = b'\xfe'  # Version Information Response

# At the moment I am not sure what/if the following dictionary will be used?
# It is here to describe the relationship between Cluster ID and Cmd.
# One day this may be used by the process_message() function and link with the parse_xxxxx() functions?
alertme_cluster_cmds = {
    CLUSTER_ID_AM_SWITCH: {
        CLUSTER_CMD_AM_STATE_REQ: "Relay State Request (SmartPlug)",
        CLUSTER_CMD_AM_STATE_CHANGE: "Relay State Change (SmartPlug)",
        CLUSTER_CMD_AM_STATE_RESP: "Switch Status Update"
    },
    CLUSTER_ID_AM_POWER: {
        CLUSTER_CMD_AM_PWR_DEMAND: "Power Demand Update",
        CLUSTER_CMD_AM_PWR_CONSUMPTION: "Power Consumption & Uptime Update",
        CLUSTER_CMD_AM_PWR_UNKNOWN: "Unknown British Gas Power Meter Update"
    },
    CLUSTER_ID_AM_STATUS: {
        CLUSTER_CMD_AM_MODE_REQ: "Mode Change Request",
        CLUSTER_CMD_AM_STATUS: "Status Update"
    },
    CLUSTER_ID_AM_TAMPER: {},
    CLUSTER_ID_AM_BUTTON: {},
    CLUSTER_ID_AM_DISCOVERY: {
        CLUSTER_CMD_AM_RSSI: "RSSI Range Test Update",
        CLUSTER_CMD_AM_VERSION_REQ: "Version Information Request",
        CLUSTER_CMD_AM_VERSION_RESP: "Version Information Response"
    },
    CLUSTER_ID_AM_SECURITY: {
        CLUSTER_CMD_AM_SECURITY: "Security Command"
    }
}

# This messages dict holds the skellington for the various ZDO and AlertMe messages. 
# it is used in conjunction with get_message() to generate the messages. 
# Those with a lambda in the data key make use of the generate_xxxx() functions 
# to generate the data based on parameters pasded.
messages = {
    'version_info_request': {
        'name': 'Version Info Request',
        'frame': {
            'profile': PROFILE_ID_ALERTME,
            'cluster': CLUSTER_ID_AM_DISCOVERY,
            'src_endpoint': ENDPOINT_ALERTME,
            'dest_endpoint': ENDPOINT_ALERTME,
            'data': lambda params: generate_version_info_request(params)
        }
    },
    'version_info_update': {
        'name': 'Version Info Update',
        'frame': {
            'profile': PROFILE_ID_ALERTME,
            'cluster': CLUSTER_ID_AM_DISCOVERY,
            'src_endpoint': ENDPOINT_ALERTME,
            'dest_endpoint': ENDPOINT_ALERTME,
            'data': lambda params: generate_version_info_update(params)
{'fraction_non_alphanumeric': 0.08533762705041763, 'fraction_numerical': 0.0241521585991748, 'mean_word_length': 3.613741875580316, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7277758', 'n_tokens_mistral': 3892, 'n_tokens_neox': 3763, 'n_words': 735}