wifibox.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. ]
  23. end
  24. class Milight
  25. ADDR = ['<broadcast>', 5987]
  26. attr_reader :socket
  27. def initialize
  28. @socket = UDPSocket.new
  29. socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
  30. @sequence = 0
  31. end
  32. def hex_to_bytes(s)
  33. s.strip.split(' ').map { |x| x.to_i(16) }.pack('C*')
  34. end
  35. def send(msg)
  36. socket.send(msg, 0, ADDR[0], ADDR[1])
  37. end
  38. def recv
  39. socket.recvfrom(1000)[0]
  40. end
  41. def start_session
  42. tries = 5
  43. begin
  44. Timeout.timeout(5) do
  45. 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"))
  46. msg = recv
  47. @session = msg[-3..-2].bytes
  48. end
  49. rescue Exception => e
  50. puts "Error: #{e}"
  51. retry if (tries -= 1) > 0
  52. end
  53. end
  54. def send_command(cmd, zone = 0)
  55. start_session if !@session
  56. msg = [0x80, 0, 0, 0, 0x11, @session[0], @session[1], 0, @sequence, 0]
  57. msg += cmd
  58. msg += [zone,0]
  59. msg += [msg[-11..-1].reduce(&:+)&0xFF]
  60. send(msg.pack('C*'))
  61. @sequence = (@sequence + 1) % 0xFF
  62. #recv
  63. end
  64. end
  65. def get_file(cmd, value, group)
  66. name = "../../packet_captures/sidoh_wifibox1/rgbcct_group#{group}_#{cmd}#{value.nil? ? "" : "_#{value}}"}.txt"
  67. File.expand_path(File.join(__FILE__, name))
  68. end
  69. def get_packet
  70. Net::HTTP.get('10.133.8.167', '/gateway_traffic/rgb_cct').split("\n").last.strip
  71. end
  72. milight = Milight.new
  73. (1..4).each do |group|
  74. seen_keys = Set.new
  75. last_val = 0
  76. file = get_file("unlink", nil, group)
  77. if File.exists?(file)
  78. File.read(file).split("\n").each { |x| seen_keys << x.split(' ').first }
  79. end
  80. puts "Processing: #{file}"
  81. File.open(file, 'a') do |f|
  82. while seen_keys.size < 255
  83. t = Thread.new do
  84. packet = get_packet
  85. key = packet.split(' ')[0]
  86. seen_keys << key
  87. f.write "#{packet}\n"
  88. f.flush
  89. end
  90. while %w(sleep run).include?(t.status)
  91. milight.send_command(Commands::UNLINK.call, group)
  92. sleep 0.1
  93. print "."
  94. end
  95. print '*'
  96. puts "\n#{file} - #{seen_keys.length}" if last_val < seen_keys.length
  97. last_val = seen_keys.length
  98. end
  99. end
  100. end
  101. # 10000.times do
  102. # milight.send_command(, 1).inspect
  103. # print "."
  104. # sleep 0.1
  105. # end