/pyhap/util.py

https://github.com/ikalchev/HAP-python · Python · 149 lines · 58 code · 28 blank · 63 comment · 14 complexity · b80863832ccc1f27b70783cbd7662a56 MD5 · raw file

  1. import asyncio
  2. import base64
  3. import socket
  4. import random
  5. import binascii
  6. import sys
  7. ALPHANUM = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  8. HEX_DIGITS = '0123456789ABCDEF'
  9. rand = random.SystemRandom()
  10. def get_local_address():
  11. """
  12. Grabs the local IP address using a socket.
  13. :return: Local IP Address in IPv4 format.
  14. :rtype: str
  15. """
  16. # TODO: try not to talk 8888 for this
  17. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  18. try:
  19. s.connect(("8.8.8.8", 80))
  20. addr = s.getsockname()[0]
  21. finally:
  22. s.close()
  23. return addr
  24. def long_to_bytes(n):
  25. """
  26. Convert a ``long int`` to ``bytes``
  27. :param n: Long Integer
  28. :type n: int
  29. :return: ``long int`` in ``bytes`` format.
  30. :rtype: bytes
  31. """
  32. byteList = list()
  33. x = 0
  34. off = 0
  35. while x != n:
  36. b = (n >> off) & 0xFF
  37. byteList.append(b)
  38. x = x | (b << off)
  39. off += 8
  40. byteList.reverse()
  41. return bytes(byteList)
  42. def generate_mac():
  43. """
  44. Generates a fake mac address used in broadcast.
  45. :return: MAC address in format XX:XX:XX:XX:XX:XX
  46. :rtype: str
  47. """
  48. return "{}{}:{}{}:{}{}:{}{}:{}{}:{}{}".format(
  49. *(rand.choice(HEX_DIGITS) for _ in range(12)))
  50. def generate_setup_id():
  51. """
  52. Generates a random Setup ID for an ``Accessory`` or ``Bridge``.
  53. Used in QR codes and the setup hash.
  54. :return: 4 digit alphanumeric code.
  55. :rtype: str
  56. """
  57. return ''.join([
  58. rand.choice(ALPHANUM)
  59. for i in range(4)
  60. ])
  61. def generate_pincode():
  62. """
  63. Generates a random pincode.
  64. :return: pincode in format ``xxx-xx-xxx``
  65. :rtype: bytearray
  66. """
  67. return '{}{}{}-{}{}-{}{}{}'.format(
  68. *(rand.randint(0, 9) for i in range(8))
  69. ).encode('ascii')
  70. def b2hex(bts):
  71. """Produce a hex string representation of the given bytes.
  72. :param bts: bytes to convert to hex.
  73. :type bts: bytes
  74. :rtype: str
  75. """
  76. return binascii.hexlify(bts).decode("ascii")
  77. def hex2b(hex_str):
  78. """Produce bytes from the given hex string representation.
  79. :param hex: hex string
  80. :type hex: str
  81. :rtype: bytes
  82. """
  83. return binascii.unhexlify(hex_str.encode("ascii"))
  84. tohex = bytes.hex if sys.version_info >= (3, 5) else b2hex
  85. """Python-version-agnostic tohex function. Equivalent to bytes.hex in python 3.5+.
  86. """
  87. fromhex = bytes.fromhex if sys.version_info >= (3, 5) else hex2b
  88. """Python-version-agnostic fromhex function. Equivalent to bytes.fromhex in python 3.5+.
  89. """
  90. def to_base64_str(bytes_input) -> str:
  91. return base64.b64encode(bytes_input).decode('utf-8')
  92. def base64_to_bytes(str_input) -> bytes:
  93. return base64.b64decode(str_input.encode('utf-8'))
  94. def byte_bool(boolv):
  95. return b'\x01' if boolv else b'\x00'
  96. async def event_wait(event, timeout, loop=None):
  97. """Wait for the given event to be set or for the timeout to expire.
  98. :param event: The event to wait for.
  99. :type event: asyncio.Event
  100. :param timeout: The timeout for which to wait, in seconds.
  101. :type timeout: float
  102. :return: ``event.is_set()``
  103. :rtype: bool
  104. """
  105. try:
  106. await asyncio.wait_for(event.wait(), timeout, loop=loop)
  107. except asyncio.TimeoutError:
  108. pass
  109. return event.is_set()