wifibox.rb 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. require 'socket'
  2. require 'set'
  3. require 'net/http'
  4. STD_COMMAND_PREFIX = [ 0x31, 0x00, 0x00, 0x08 ]
  5. STD_COMMAND_SUFFIX = [ 0x00, 0x00, 0x00 ]
  6. class Commands
  7. def self.std_command(*cmd)
  8. ->() { STD_COMMAND_PREFIX + cmd + STD_COMMAND_SUFFIX }
  9. end
  10. def self.arg_command(prefix)
  11. ->(val) { STD_COMMAND_PREFIX + [prefix, val] + STD_COMMAND_SUFFIX }
  12. end
  13. VALUES = [
  14. LIGHT_ON = std_command(0x04, 0x01),
  15. LIGHT_OFF = std_command(0x04, 0x02),
  16. SATURATION = arg_command(0x02),
  17. BRIGHTNESS = arg_command(0x03),
  18. KELVIN = arg_command(0x05),
  19. WHITE_ON = std_command(0x05, 0x64),
  20. LINK = ->() { [ 0x3D, 0x00, 0x00, 0x08, 0x00, 0x00 ] + STD_COMMAND_SUFFIX },
  21. UNLINK = ->() { [ 0x3D, 0x00, 0x00, 0x08, 0x00, 0x00 ] + STD_COMMAND_SUFFIX },
  22. COLOR = ->(value) { STD_COMMAND_PREFIX + [0x01] + ([value]*4) }
  23. ]
  24. end
  25. class Milight
  26. ADDR = ['<broadcast>', 5987]
  27. attr_reader :socket
  28. def initialize
  29. @socket = UDPSocket.new
  30. socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
  31. @sequence = 0
  32. end
  33. def hex_to_bytes(s)
  34. s.strip.split(' ').map { |x| x.to_i(16) }.pack('C*')
  35. end
  36. def send(msg)
  37. socket.send(msg, 0, ADDR[0], ADDR[1])
  38. end
  39. def recv
  40. socket.recvfrom(1000)[0]
  41. end
  42. def start_session
  43. tries = 5
  44. begin
  45. Timeout.timeout(5) do
  46. send(hex_to_bytes("20 00 00 00 16 02 62 3A D5 ED A3 01 AE 08 2D 46 61 41 A7 F6 DC AF D3 E6 00 00 1E"))
  47. msg = recv
  48. @session = msg[-3..-2].bytes
  49. end
  50. rescue Exception => e
  51. puts "Error: #{e}"
  52. retry if (tries -= 1) > 0
  53. end
  54. end
  55. def send_command(cmd, zone = 0)
  56. start_session if !@session
  57. msg = [0x80, 0, 0, 0, 0x11, @session[0], @session[1], 0, @sequence, 0]
  58. msg += cmd
  59. msg += [zone,0]
  60. msg += [msg[-11..-1].reduce(&:+)&0xFF]
  61. send(msg.pack('C*'))
  62. @sequence = (@sequence + 1) % 0xFF
  63. #recv
  64. end
  65. end
  66. def get_file(cmd, value, group)
  67. name = "../../packet_captures/sidoh_wifibox1/rgbcct_group#{group}_#{cmd}#{value.nil? ? "" : "_#{value}"}.txt"
  68. File.expand_path(File.join(__FILE__, name))
  69. end
  70. def get_packet
  71. Net::HTTP.get('10.133.8.167', '/gateway_traffic/rgb_cct').split("\n").last.strip
  72. end
  73. milight = Milight.new
  74. (1..4).each do |group|
  75. (0..0xFF).each do |value|
  76. seen_keys = Set.new
  77. last_val = 0
  78. file = get_file("color", value, group)
  79. if File.exists?(file)
  80. File.read(file).split("\n").each { |x| seen_keys << x.split(' ').first }
  81. end
  82. puts "Processing: #{file}"
  83. File.open(file, 'a') do |f|
  84. while seen_keys.size < 255
  85. t = Thread.new do
  86. packet = get_packet
  87. key = packet.split(' ')[0]
  88. seen_keys << key
  89. f.write "#{packet}\n"
  90. f.flush
  91. end
  92. while %w(sleep run).include?(t.status)
  93. milight.send_command(Commands::COLOR.call(value), group)
  94. sleep 0.1
  95. print "."
  96. end
  97. print '*'
  98. puts "\n#{file} - #{seen_keys.length}" if last_val < seen_keys.length
  99. last_val = seen_keys.length
  100. end
  101. end
  102. end
  103. end
  104. # 10000.times do
  105. # milight.send_command(, 1).inspect
  106. # print "."
  107. # sleep 0.1
  108. # end