Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.4 KiB

  1. #!/usr/bin/env python
  2. #-------------------------------------------------------------------------------
  3. # ESPurna OTA manager
  4. # xose.perez@gmail.com
  5. #
  6. # Requires PlatformIO Core
  7. #-------------------------------------------------------------------------------
  8. import sys
  9. import re
  10. import logging
  11. import socket
  12. import argparse
  13. import subprocess
  14. from time import sleep
  15. from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf
  16. #-------------------------------------------------------------------------------
  17. devices = []
  18. description = "ESPurna OTA Manager v0.1"
  19. #-------------------------------------------------------------------------------
  20. def on_service_state_change(zeroconf, service_type, name, state_change):
  21. '''
  22. Callback that adds discovered devices to "devices" list
  23. '''
  24. if state_change is ServiceStateChange.Added:
  25. info = zeroconf.get_service_info(service_type, name)
  26. if info:
  27. hostname = info.server.split(".")[0]
  28. device = {
  29. 'hostname': hostname.upper(),
  30. 'ip': socket.inet_ntoa(info.address)
  31. }
  32. device['app'] = info.properties.get('app_name', '')
  33. device['version'] = info.properties.get('app_version', '')
  34. device['device'] = info.properties.get('target_board', '')
  35. device['mem_size'] = info.properties.get('mem_size', '')
  36. device['sdk_size'] = info.properties.get('sdk_size', '')
  37. devices.append(device)
  38. def list():
  39. '''
  40. Shows the list of discovered devices
  41. '''
  42. output_format="{:>3} {:<25}{:<25}{:<15}{:<15}{:<30}{:<10}{:<10}"
  43. print(output_format.format(
  44. "#",
  45. "HOSTNAME",
  46. "IP",
  47. "APP",
  48. "VERSION",
  49. "DEVICE",
  50. "MEM_SIZE",
  51. "SDK_SIZE",
  52. ))
  53. print "-" * 135
  54. index = 0
  55. for device in devices:
  56. index = index + 1
  57. print(output_format.format(
  58. index,
  59. device.get('hostname', ''),
  60. device.get('ip', ''),
  61. device.get('app', ''),
  62. device.get('version', ''),
  63. device.get('device', ''),
  64. device.get('mem_size', ''),
  65. device.get('sdk_size', ''),
  66. ))
  67. print
  68. def get_boards():
  69. '''
  70. Grabs board types fro hardware.h file
  71. '''
  72. boards = []
  73. for line in open("espurna/config/hardware.h"):
  74. m = re.search(r'defined\((\w*)\)', line)
  75. if m:
  76. boards.append(m.group(1))
  77. return sorted(boards)
  78. def flash():
  79. '''
  80. Grabs info from the user about what device to flash
  81. '''
  82. # Choose the board
  83. try:
  84. index = int(input("Choose the board you want to flash (empty if none of these): "))
  85. except:
  86. index = 0
  87. if index < 0 or len(devices) < index:
  88. print "Board number must be between 1 and %s\n" % str(len(devices))
  89. return None
  90. board = {'board': '', 'ip': '', 'size': 0 , 'auth': '', 'flags': ''}
  91. if index > 0:
  92. device = devices[index-1]
  93. board['board'] = device.get('device', '')
  94. board['ip'] = device.get('ip', '')
  95. board['size'] = int(device.get('mem_size', 0) if device.get('mem_size', 0) == device.get('sdk_size', 0) else 0) / 1024
  96. # Choose board type if none before
  97. if len(board['board']) == 0:
  98. print
  99. count = 1
  100. boards = get_boards()
  101. for name in boards:
  102. print "%3d\t%s" % (count, name)
  103. count = count + 1
  104. print
  105. try:
  106. index = int(input("Choose the board type you want to flash: "))
  107. except:
  108. index = 0
  109. if index < 1 or len(boards) < index:
  110. print "Board number must be between 1 and %s\n" % str(len(boards))
  111. return None
  112. board['board'] = boards[index-1]
  113. # Choose board size of none before
  114. if board['size'] == 0:
  115. try:
  116. board['size'] = int(input("Board memory size (1 for 1M, 4 for 4M): "))
  117. except:
  118. print "Wrong memory size"
  119. return None
  120. # Choose IP of none before
  121. if len(board['ip']) == 0:
  122. try:
  123. board['ip'] = raw_input("IP of the device to flash (empty for 192.168.4.1): ") or "192.168.4.1"
  124. except:
  125. print "Wrong IP"
  126. return None
  127. board['auth'] = raw_input("Authorization key of the device to flash: ")
  128. board['flags'] = raw_input("Extra flags for the build: ")
  129. return board
  130. def run(device, env):
  131. command = "export ESPURNA_IP=\"%s\"; export ESPURNA_BOARD=\"%s\"; export ESPURNA_AUTH=\"%s\"; export ESPURNA_FLAGS=\"%s\"; platformio run --silent --environment %s -t upload"
  132. command = command % (device['ip'], device['board'], device['auth'], device['flags'], env)
  133. subprocess.check_call(command, shell=True)
  134. #-------------------------------------------------------------------------------
  135. if __name__ == '__main__':
  136. # Parse command line options
  137. parser = argparse.ArgumentParser(description=description)
  138. #parser.add_argument("-v", "--verbose", help="show verbose output", default=0, action='count')
  139. parser.add_argument("-f", "--flash", help="flash device", default=0, action='count')
  140. parser.add_argument("-s", "--sort", help="sort devices list by field", default='hostname')
  141. args = parser.parse_args()
  142. print
  143. print description
  144. print
  145. # Enable logging if verbose
  146. #logging.basicConfig(level=logging.DEBUG)
  147. #logging.getLogger('zeroconf').setLevel(logging.DEBUG)
  148. # Look for sevices
  149. zeroconf = Zeroconf()
  150. browser = ServiceBrowser(zeroconf, "_arduino._tcp.local.", handlers=[on_service_state_change])
  151. sleep(1)
  152. zeroconf.close()
  153. # Sort list
  154. field = args.sort.lower()
  155. if field not in devices[0]:
  156. print "Unknown field '%s'\n" % field
  157. sys.exit(1)
  158. devices = sorted(devices, key=lambda device: device.get(field, ''))
  159. # List devices
  160. list()
  161. # Flash device
  162. if args.flash > 0:
  163. device = flash()
  164. if device:
  165. env = "esp8266-%sm-ota" % device['size']
  166. # Summary
  167. print
  168. print "ESPURNA_IP = %s" % device['ip']
  169. print "ESPURNA_BOARD = %s" % device['board']
  170. print "ESPURNA_AUTH = %s" % device['auth']
  171. print "ESPURNA_FLAGS = %s" % device['flags']
  172. print "ESPURNA_ENV = %s" % env
  173. response = raw_input("\nAre these values right [y/N]: ")
  174. print
  175. if response == "y":
  176. run(device, env)