Source code for digi.xbee.models.address

# Copyright 2017-2021, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import re
from digi.xbee.util import utils


[docs]class XBee16BitAddress: """ This class represent a 16-bit network address. This address is only applicable for: 1. 802.15.4 2. Zigbee 3. ZNet 2.5 4. XTend (Legacy) DigiMesh and Point-to-multipoint does not support 16-bit addressing. Each device has its own 16-bit address which is unique in the network. It is automatically assigned when the radio joins the network for Zigbee and Znet 2.5, and manually configured in 802.15.4 radios. | Attributes: | **COORDINATOR_ADDRESS** (XBee16BitAddress): 16-bit address reserved for the coordinator. | **BROADCAST_ADDRESS** (XBee16BitAddress): 16-bit broadcast address. | **UNKNOWN_ADDRESS** (XBee16BitAddress): 16-bit unknown address. | **PATTERN** (String): Pattern for the 16-bit address string: `(0[xX])?[0-9a-fA-F]{1,4}` """ PATTERN = "^(0[xX])?[0-9a-fA-F]{1,4}$" """ 16-bit address string pattern. """ COORDINATOR_ADDRESS = None """ 16-bit address reserved for the coordinator (value: 0000). """ BROADCAST_ADDRESS = None """ 16-bit broadcast address (value: FFFF). """ UNKNOWN_ADDRESS = None """ 16-bit unknown address (value: FFFE). """ __REGEXP = re.compile(PATTERN) def __init__(self, address): """ Class constructor. Instantiates a new :class:`.XBee16BitAddress` object with the provided parameters. Args: address (Bytearray): address as byte array. Must be 1-2 digits. Raises: TypeError: if `address` is `None`. ValueError: if `address` is `None` or has less than 1 byte or more than 2. """ if not address: raise ValueError("Address must contain at least 1 byte") if len(address) > 2: raise ValueError("Address can't contain more than 2 bytes") if len(address) == 1: address.insert(0, 0) self.__address = address
[docs] @classmethod def from_hex_string(cls, address): """ Class constructor. Instantiates a new :`.XBee16BitAddress` object from the provided hex string. Args: address (String): String containing the address. Must be made by hex. digits without blanks. Minimum 1 character, maximum 4 (16-bit). Raises: ValueError: if `address` has less than 1 character. ValueError: if `address` contains non-hexadecimal characters. """ if not address: raise ValueError("Address must contain at least 1 digit") if not cls.__REGEXP.match(address): raise ValueError("Address must follow this pattern: " + cls.PATTERN) return cls(utils.hex_string_to_bytes(address))
[docs] @classmethod def from_bytes(cls, hsb, lsb): """ Class constructor. Instantiates a new :`.XBee16BitAddress` object from the provided high significant byte and low significant byte. Args: hsb (Integer): high significant byte of the address. lsb (Integer): low significant byte of the address. Raises: ValueError: if `lsb` is less than 0 or greater than 255. ValueError: if `hsb` is less than 0 or greater than 255. """ if hsb > 255 or hsb < 0: raise ValueError("HSB must be between 0 and 255.") if lsb > 255 or lsb < 0: raise ValueError("LSB must be between 0 and 255.") return cls(bytearray([hsb, lsb]))
[docs] @classmethod def is_valid(cls, address): """ Checks if the provided hex string is a valid 16-bit address. Args: address (String or Bytearray, or :class:`.XBee16BitAddress`): String: String with the address only with hex digits without blanks. Minimum 1 character, maximum 4 (16-bit). Bytearray: Address as byte array. Must be 1-2 digits. Returns: Boolean: `True` for a valid 16-bit address, `False` otherwise. """ if isinstance(address, XBee16BitAddress): return True if isinstance(address, bytearray): return 1 <= len(address) <= 2 if isinstance(address, str): return bool(cls.__REGEXP.match(address)) return False
[docs] @classmethod def is_known_node_addr(cls, address): """ Checks if a provided address is a known value. That is, if it is a valid 16-bit address and it is not the unknown or the broadcast address. Args: address (String, Bytearray, or :class:`.XBee16BitAddress`): The 16-bit address to check as a string, bytearray or :class:`.XBee16BitAddress`. Returns: Boolean: `True` for a known node 16-bit address, `False` otherwise. """ if not cls.is_valid(address): return False if isinstance(address, str): address = XBee16BitAddress.from_hex_string(address) elif isinstance(address, bytearray): address = XBee16BitAddress(address) return address not in (XBee16BitAddress.BROADCAST_ADDRESS, XBee16BitAddress.UNKNOWN_ADDRESS)
def __get_item__(self, index): """ Operator [] Args: index (Integer): index to be accessed. Returns: Integer. 'index' component of the address bytearray. """ return self.__address.__get_item__(index) def __str__(self): """ Called by the str() built-in function and by the print statement to compute the "informal" string representation of an object. This differs from __repr__() in that it does not have to be a valid Python expression: a more convenient or concise representation may be used instead. Returns: String: "informal" representation of this XBee16BitAddress. """ return utils.hex_to_string(self.__address, pretty=False) def __hash__(self): """ Returns a hash code value for the object. Returns: Integer: hash code value for the object. """ res = 23 for byte in self.__address: res = 31 * (res + byte) return res def __eq__(self, other): """ Operator == Args: other (:class`.XBee16BitAddress`): another XBee16BitAddress object. Returns: Boolean: `True` if self and other have the same value and type, `False` in other case. """ if not isinstance(other, XBee16BitAddress): return False return self.address == other.address def __iter__(self): """ Gets an iterator class of this instance address. Returns: Iterator: iterator of this address. """ return self.__address.__iter__()
[docs] def get_hsb(self): """ Returns the high part of the bytearray (component 0). Returns: Integer: high part of the bytearray. """ return self.__address[0]
[docs] def get_lsb(self): """ Returns the low part of the bytearray (component 1). Returns: Integer: low part of the bytearray. """ return self.__address[1]
@property def address(self): """ Returns a bytearray representation of this XBee16BitAddress. Returns: Bytearray: bytearray representation of this XBee16BitAddress. """ return bytearray(self.__address)
XBee16BitAddress.COORDINATOR_ADDRESS = XBee16BitAddress.from_hex_string("0000") XBee16BitAddress.BROADCAST_ADDRESS = XBee16BitAddress.from_hex_string("FFFF") XBee16BitAddress.UNKNOWN_ADDRESS = XBee16BitAddress.from_hex_string("FFFE")
[docs]class XBee64BitAddress: """ This class represents a 64-bit address (also known as MAC address). The 64-bit address is a unique device address assigned during manufacturing. This address is unique to each physical device. """ PATTERN = "^(0[xX])?[0-9a-fA-F]{1,16}$" """ 64-bit address string pattern. """ COORDINATOR_ADDRESS = None """ 64-bit address reserved for the coordinator (value: 0000000000000000). """ BROADCAST_ADDRESS = None """ 64-bit broadcast address (value: 000000000000FFFF). """ UNKNOWN_ADDRESS = None """ 64-bit unknown address (value: FFFFFFFFFFFFFFFF). """ __REGEXP = re.compile(PATTERN) def __init__(self, address): """ Class constructor. Instantiates a new :class:`.XBee64BitAddress` object with the provided parameters. Args: address (Bytearray): the XBee 64-bit address as byte array. Raise: ValueError: if `address` is `None` or its length less than 1 or greater than 8. """ if not address: raise ValueError("Address must contain at least 1 byte") if len(address) > 8: raise ValueError("Address cannot contain more than 8 bytes") self.__address = bytearray(8) diff = 8 - len(address) for i in range(diff): self.__address[i] = 0 for i in range(diff, 8): self.__address[i] = address[i - diff]
[docs] @classmethod def from_hex_string(cls, address): """ Class constructor. Instantiates a new :class:`.XBee64BitAddress` object from the provided hex string. Args: address (String): The XBee 64-bit address as a string. Raises: ValueError: if the address' length is less than 1 or does not match with the pattern: `(0[xX])?[0-9a-fA-F]{1,16}`. """ if not address: raise ValueError("Address must contain at least 1 byte") if not cls.__REGEXP.match(address): raise ValueError("Address must follow this pattern: " + cls.PATTERN) return cls(utils.hex_string_to_bytes(address))
[docs] @classmethod def from_bytes(cls, *args): """ Class constructor. Instantiates a new :class:`.XBee64BitAddress` object from the provided bytes. Args: args (8 Integers): 8 integers that represent the bytes 1 to 8 of this XBee64BitAddress. Raises: ValueError: if the amount of arguments is not 8 or if any of the arguments is not between 0 and 255. """ if len(args) != 8: raise ValueError("Number of bytes given as arguments must be 8.") for i, val in enumerate(args): if val > 255 or val < 0: raise ValueError("Byte " + str(i + 1) + " must be between 0 and 255") return cls(bytearray(args))
[docs] @classmethod def is_valid(cls, address): """ Checks if the provided hex string is a valid 64-bit address. Args: address (String, Bytearray, or :class:`.XBee64BitAddress`): String: String with the address only with hex digits without blanks. Minimum 1 character, maximum 16 (64-bit). Bytearray: Address as byte array. Must be 1-8 digits. Returns Boolean: `True` for a valid 64-bit address, `False` otherwise. """ if isinstance(address, XBee64BitAddress): return True if isinstance(address, bytearray): return 1 <= len(address) <= 8 if isinstance(address, str): return bool(cls.__REGEXP.match(address)) return False
[docs] @classmethod def is_known_node_addr(cls, address): """ Checks if a provided address is a known value. That is, if it is a valid 64-bit address and it is not the unknown or the broadcast address. Args: address (String, Bytearray, or :class:`.XBee64BitAddress`): The 64-bit address to check as a string, bytearray or :class:`.XBee64BitAddress`. Returns: Boolean: `True` for a known node 64-bit address, `False` otherwise. """ if not cls.is_valid(address): return False if isinstance(address, str): address = XBee64BitAddress.from_hex_string(address) elif isinstance(address, bytearray): address = XBee64BitAddress(address) return address not in (XBee64BitAddress.BROADCAST_ADDRESS, XBee64BitAddress.UNKNOWN_ADDRESS)
def __str__(self): """ Called by the str() built-in function and by the print statement to compute the "informal" string representation of an object. This differs from __repr__() in that it does not have to be a valid Python expression: a more convenient or concise representation may be used instead. Returns: String: "informal" representation of this XBee64BitAddress. """ return "".join(["%02X" % i for i in self.__address]) def __hash__(self): """ Returns a hash code value for the object. Returns: Integer: hash code value for the object. """ res = 23 for byte in self.__address: res = 31 * (res + byte) return res def __eq__(self, other): """ Operator == Args: other: another XBee64BitAddress. Returns: Boolean: `True` if self and other have the same value and type, `False` in other case. """ if other is None: return False if not isinstance(other, XBee64BitAddress): return False return self.address == other.address def __iter__(self): """ Gets an iterator class of this instance address. Returns: Iterator: iterator of this address. """ return self.__address.__iter__() @property def address(self): """ Returns a bytearray representation of this XBee64BitAddress. Returns: Bytearray: bytearray representation of this XBee64BitAddress. """ return bytearray(self.__address)
XBee64BitAddress.COORDINATOR_ADDRESS = XBee64BitAddress.from_hex_string("0000") XBee64BitAddress.BROADCAST_ADDRESS = XBee64BitAddress.from_hex_string("FFFF") XBee64BitAddress.UNKNOWN_ADDRESS = XBee64BitAddress.from_hex_string("F"*16)
[docs]class XBeeIMEIAddress: """ This class represents an IMEI address used by cellular devices. This address is only applicable for Cellular protocol. """ PATTERN = r"^\d{0,15}$" """ IMEI address string pattern. """ __REGEXP = re.compile(PATTERN) def __init__(self, address): """ Class constructor. Instantiates a new :`.XBeeIMEIAddress` object with the provided parameters. Args: address (Bytearray): The XBee IMEI address as byte array. Raises: ValueError: if `address` is `None`. ValueError: if length of `address` greater than 8. """ if address is None: raise ValueError("IMEI address cannot be None") if len(address) > 8: raise ValueError("IMEI address cannot be longer than 8 bytes") self.__address = self.__generate_byte_array(address)
[docs] @classmethod def from_string(cls, address): """ Class constructor. Instantiates a new :`.XBeeIMEIAddress` object from the provided string. Args: address (String): The XBee IMEI address as a string. Raises: ValueError: if `address` is `None`. ValueError: if `address` does not match the pattern: `^\\d{0,15}$`. """ if address is None: raise ValueError("IMEI address cannot be None") if not cls.__REGEXP.match(address): raise ValueError("Address must follow this pattern: " + cls.PATTERN) return cls(utils.hex_string_to_bytes(address))
[docs] @classmethod def is_valid(cls, address): """ Checks if the provided hex string is a valid IMEI. Args: address (String or Bytearray): The XBee IMEI address as a string or bytearray. Returns: Boolean: `True` for a valid IMEI, `False` otherwise. """ if isinstance(address, bytearray): return len(address) >= 8 if isinstance(address, str): return cls.__REGEXP.match(address) return False
@staticmethod def __generate_byte_array(byte_address): """ Generates the IMEI byte address based on the given byte array. Args: byte_address (Bytearray): the byte array used to generate the final IMEI byte address. Returns: Bytearray: the IMEI in byte array format. """ # Pad zeros in the MSB of the address return bytearray(8 - len(byte_address)) + byte_address @property def address(self): """ Returns a string representation of this XBeeIMEIAddress. Returns: String: the IMEI address in string format. """ return "".join(["%02X" % i for i in self.__address])[1:] def __str__(self): """ Called by the str() built-in function and by the print statement to compute the "informal" string representation of an object. This differs from __repr__() in that it does not have to be a valid Python expression: a more convenient or concise representation may be used instead. Returns: String: "informal" representation of this XBeeIMEIAddress. """ return self.address def __hash__(self): """ Returns a hash code value for the object. Returns: Integer: hash code value for the object. """ res = 23 for byte in self.__address: res = 31 * (res + byte) return res def __eq__(self, other): """ Operator == Args: other (:class:`.XBeeIMEIAddress`): another XBeeIMEIAddress. Returns: Boolean: `True` if self and other have the same value and type, `False` in other case. """ if other is None: return False if not isinstance(other, XBeeIMEIAddress): return False return self.address == other.address