ruby_home 0.2.1 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +41 -0
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +2 -9
  5. data/.standard.yml +3 -0
  6. data/CHANGELOG.md +18 -0
  7. data/Gemfile +2 -2
  8. data/README.md +40 -77
  9. data/Rakefile +4 -4
  10. data/examples/air_purifier.rb +66 -0
  11. data/examples/air_quality_sensor.rb +119 -0
  12. data/examples/battery_service.rb +58 -0
  13. data/examples/carbon_dioxide_sensor.rb +78 -0
  14. data/examples/carbon_monoxide_sensor.rb +78 -0
  15. data/examples/contact_sensor.rb +66 -0
  16. data/examples/door.rb +48 -0
  17. data/examples/fan.rb +30 -0
  18. data/examples/fan_v2.rb +68 -0
  19. data/examples/garage_door_opener.rb +71 -0
  20. data/examples/heater_cooler.rb +92 -0
  21. data/examples/humidifier_dehumidifier.rb +88 -0
  22. data/examples/humidity_sensor.rb +62 -0
  23. data/examples/leak_sensor.rb +66 -0
  24. data/examples/light_sensor.rb +64 -0
  25. data/examples/lightbulb.rb +31 -0
  26. data/examples/lock_mechanism.rb +34 -0
  27. data/examples/motion_sensor.rb +66 -0
  28. data/examples/occupancy_sensor.rb +66 -0
  29. data/examples/outlet.rb +29 -0
  30. data/examples/security_system.rb +53 -0
  31. data/examples/smoke_sensor.rb +66 -0
  32. data/examples/switch.rb +16 -0
  33. data/examples/television.rb +73 -0
  34. data/examples/temperature_sensor.rb +62 -0
  35. data/examples/thermostat.rb +113 -0
  36. data/examples/window.rb +48 -0
  37. data/examples/window_covering.rb +72 -0
  38. data/lib/ruby_home.rb +21 -22
  39. data/lib/ruby_home/accessory.rb +1 -1
  40. data/lib/ruby_home/accessory_collection.rb +6 -6
  41. data/lib/ruby_home/accessory_info.rb +18 -18
  42. data/lib/ruby_home/characteristic.rb +13 -7
  43. data/lib/ruby_home/characteristic_collection.rb +13 -13
  44. data/lib/ruby_home/config/categories.yml +39 -0
  45. data/lib/ruby_home/config/characteristics.yml +190 -319
  46. data/lib/ruby_home/config/manual_characteristics.yml +278 -0
  47. data/lib/ruby_home/config/manual_services.yml +45 -0
  48. data/lib/ruby_home/config/services.yml +338 -304
  49. data/lib/ruby_home/configuration.rb +21 -2
  50. data/lib/ruby_home/device_id.rb +3 -3
  51. data/lib/ruby_home/dns/service.rb +4 -6
  52. data/lib/ruby_home/dns/text_record.rb +10 -10
  53. data/lib/ruby_home/errors.rb +1 -0
  54. data/lib/ruby_home/factories/characteristic_factory.rb +38 -37
  55. data/lib/ruby_home/factories/service_factory.rb +72 -72
  56. data/lib/ruby_home/factories/templates/characteristic_template.rb +6 -6
  57. data/lib/ruby_home/factories/templates/service_template.rb +12 -11
  58. data/lib/ruby_home/hap/crypto/chacha20poly1305.rb +2 -2
  59. data/lib/ruby_home/hap/crypto/hkdf.rb +4 -4
  60. data/lib/ruby_home/hap/crypto/session_key.rb +7 -7
  61. data/lib/ruby_home/hap/decrypter.rb +8 -8
  62. data/lib/ruby_home/hap/encrypter.rb +5 -6
  63. data/lib/ruby_home/hap/ev_response.rb +17 -17
  64. data/lib/ruby_home/hap/hap_request.rb +1 -1
  65. data/lib/ruby_home/hap/server.rb +4 -4
  66. data/lib/ruby_home/hap/server_handler.rb +8 -10
  67. data/lib/ruby_home/hap/session.rb +22 -22
  68. data/lib/ruby_home/hap/values/base_value.rb +3 -3
  69. data/lib/ruby_home/hap/values/bool_value.rb +4 -4
  70. data/lib/ruby_home/hap/values/float_value.rb +4 -4
  71. data/lib/ruby_home/hap/values/identify_value.rb +1 -1
  72. data/lib/ruby_home/hap/values/int32_value.rb +4 -4
  73. data/lib/ruby_home/hap/values/null_value.rb +1 -1
  74. data/lib/ruby_home/hap/values/string_value.rb +11 -11
  75. data/lib/ruby_home/hap/values/uint32_value.rb +5 -5
  76. data/lib/ruby_home/hap/values/uint8_value.rb +14 -14
  77. data/lib/ruby_home/hex_helper.rb +3 -3
  78. data/lib/ruby_home/http/application.rb +7 -7
  79. data/lib/ruby_home/http/controllers/accessories_controller.rb +3 -3
  80. data/lib/ruby_home/http/controllers/application_controller.rb +6 -6
  81. data/lib/ruby_home/http/controllers/characteristics_controller.rb +29 -29
  82. data/lib/ruby_home/http/controllers/identify_controller.rb +10 -10
  83. data/lib/ruby_home/http/controllers/pair_setups_controller.rb +19 -19
  84. data/lib/ruby_home/http/controllers/pair_verifies_controller.rb +9 -9
  85. data/lib/ruby_home/http/controllers/pairings_controller.rb +6 -6
  86. data/lib/ruby_home/http/serializers/accessory_serializer.rb +5 -5
  87. data/lib/ruby_home/http/serializers/characteristic_serializer.rb +27 -19
  88. data/lib/ruby_home/http/serializers/characteristic_value_serializer.rb +5 -5
  89. data/lib/ruby_home/http/serializers/object_serializer.rb +1 -1
  90. data/lib/ruby_home/http/serializers/service_serializer.rb +19 -9
  91. data/lib/ruby_home/http/serializers/uuid_helper.rb +2 -2
  92. data/lib/ruby_home/http/services/session_notifier.rb +8 -8
  93. data/lib/ruby_home/http/services/start_srp_service.rb +3 -3
  94. data/lib/ruby_home/http/services/verify_finish_service.rb +22 -22
  95. data/lib/ruby_home/http/services/verify_srp_service.rb +22 -22
  96. data/lib/ruby_home/identifier_cache.rb +4 -5
  97. data/lib/ruby_home/password.rb +14 -14
  98. data/lib/ruby_home/persistable.rb +19 -12
  99. data/lib/ruby_home/service.rb +5 -2
  100. data/lib/ruby_home/service_collection.rb +1 -1
  101. data/lib/ruby_home/version.rb +1 -1
  102. data/rubyhome.gemspec +31 -31
  103. data/sbin/characteristic_generator.rb +22 -24
  104. data/sbin/service_generator.rb +38 -19
  105. metadata +85 -44
  106. data/.travis.yml +0 -31
@@ -1,10 +1,10 @@
1
- require_relative 'application_controller'
1
+ require_relative "application_controller"
2
2
 
3
3
  module RubyHome
4
4
  module HTTP
5
5
  class PairingsController < ApplicationController
6
- post '/' do
7
- content_type 'application/pairing+tlv8'
6
+ post "/" do
7
+ content_type "application/pairing+tlv8"
8
8
 
9
9
  case unpack_request[:method]
10
10
  when 3
@@ -20,9 +20,9 @@ module RubyHome
20
20
  pairing_params = {
21
21
  admin: !!unpack_request[:permissions],
22
22
  identifier: unpack_request[:identifier],
23
- public_key: unpack_request[:public_key].unpack1('H*')
23
+ public_key: unpack_request[:public_key].unpack1("H*")
24
24
  }
25
- accessory_info.add_paired_client pairing_params
25
+ accessory_info.add_paired_client(**pairing_params)
26
26
 
27
27
  tlv state: 2
28
28
  end
@@ -30,7 +30,7 @@ module RubyHome
30
30
  def remove_pairing
31
31
  accessory_info.remove_paired_client(unpack_request[:identifier])
32
32
 
33
- response['connection'] = 'close'
33
+ response["connection"] = "close"
34
34
  tlv state: 2
35
35
  end
36
36
  end
@@ -1,5 +1,5 @@
1
- require_relative 'object_serializer'
2
- require_relative 'service_serializer'
1
+ require_relative "object_serializer"
2
+ require_relative "service_serializer"
3
3
 
4
4
  module RubyHome
5
5
  module HTTP
@@ -7,13 +7,13 @@ module RubyHome
7
7
  include ObjectSerializer
8
8
 
9
9
  def root
10
- 'accessories'
10
+ "accessories"
11
11
  end
12
12
 
13
13
  def record_hash(accessory)
14
14
  {
15
- 'aid' => accessory.id,
16
- 'services' => ServiceSerializer.new(accessory.services).serializable_hash,
15
+ "aid" => accessory.id,
16
+ "services" => ServiceSerializer.new(accessory.services).serializable_hash
17
17
  }
18
18
  end
19
19
  end
@@ -1,5 +1,5 @@
1
- require_relative 'object_serializer'
2
- require_relative 'uuid_helper'
1
+ require_relative "object_serializer"
2
+ require_relative "uuid_helper"
3
3
 
4
4
  module RubyHome
5
5
  module HTTP
@@ -9,31 +9,39 @@ module RubyHome
9
9
 
10
10
  def record_hash(characteristic)
11
11
  {
12
- 'iid' => characteristic.instance_id,
13
- 'type' => uuid_short_form(characteristic.uuid),
14
- 'perms' => perms(characteristic),
15
- 'format' => characteristic.format,
16
- 'description' => characteristic.description,
17
- }.merge(value_hash(characteristic))
12
+ "iid" => characteristic.instance_id,
13
+ "type" => uuid_short_form(characteristic.uuid),
14
+ "perms" => perms(characteristic),
15
+ "format" => characteristic.format,
16
+ "description" => characteristic.description
17
+ }
18
+ .merge(value_hash(characteristic))
19
+ .merge(valid_values_hash(characteristic))
18
20
  end
19
21
 
20
22
  private
21
23
 
22
- HIDDEN_VALUE_OBJECTS = [ IdentifyValue ].freeze
24
+ def perms(characteristic)
25
+ characteristic.properties.map do |property|
26
+ RubyHome::Characteristic::PROPERTIES[property]
27
+ end.compact
28
+ end
23
29
 
24
- def perms(characteristic)
25
- characteristic.properties.map do |property|
26
- RubyHome::Characteristic::PROPERTIES[property]
27
- end.compact
30
+ def value_hash(characteristic)
31
+ if characteristic.properties.include?("read")
32
+ {"value" => characteristic.value}
33
+ else
34
+ {}
28
35
  end
36
+ end
29
37
 
30
- def value_hash(characteristic)
31
- if HIDDEN_VALUE_OBJECTS.include?(characteristic.value_object.class)
32
- {}
33
- else
34
- { 'value' => characteristic.value }.compact
35
- end
38
+ def valid_values_hash(characteristic)
39
+ if characteristic.valid_values.empty?
40
+ {}
41
+ else
42
+ {"valid-values" => characteristic.valid_values}
36
43
  end
44
+ end
37
45
  end
38
46
  end
39
47
  end
@@ -1,4 +1,4 @@
1
- require_relative 'object_serializer'
1
+ require_relative "object_serializer"
2
2
 
3
3
  module RubyHome
4
4
  module HTTP
@@ -6,14 +6,14 @@ module RubyHome
6
6
  include ObjectSerializer
7
7
 
8
8
  def root
9
- 'characteristics'
9
+ "characteristics"
10
10
  end
11
11
 
12
12
  def record_hash(characteristic)
13
13
  {
14
- 'aid' => characteristic.accessory_id,
15
- 'iid' => characteristic.instance_id,
16
- 'value' => characteristic.value,
14
+ "aid" => characteristic.accessory_id,
15
+ "iid" => characteristic.instance_id,
16
+ "value" => characteristic.value
17
17
  }
18
18
  end
19
19
  end
@@ -1,4 +1,4 @@
1
- require 'facets/hash/symbolize_keys'
1
+ require "facets/hash/symbolize_keys"
2
2
 
3
3
  module RubyHome
4
4
  module HTTP
@@ -1,6 +1,6 @@
1
- require_relative 'characteristic_serializer'
2
- require_relative 'object_serializer'
3
- require_relative 'uuid_helper'
1
+ require_relative "characteristic_serializer"
2
+ require_relative "object_serializer"
3
+ require_relative "uuid_helper"
4
4
 
5
5
  module RubyHome
6
6
  module HTTP
@@ -10,12 +10,22 @@ module RubyHome
10
10
 
11
11
  def record_hash(service)
12
12
  {
13
- 'iid' => service.instance_id,
14
- 'type' => uuid_short_form(service.uuid),
15
- 'characteristics' => CharacteristicSerializer.new(service.characteristics).serializable_hash,
16
- 'primary' => service.primary,
17
- 'hidden' => service.hidden,
18
- }
13
+ "iid" => service.instance_id,
14
+ "type" => uuid_short_form(service.uuid),
15
+ "characteristics" => CharacteristicSerializer.new(service.characteristics).serializable_hash,
16
+ "primary" => service.primary,
17
+ "hidden" => service.hidden
18
+ }.merge(linked_services(service))
19
+ end
20
+
21
+ private
22
+
23
+ def linked_services(service)
24
+ if service.linked.empty?
25
+ {}
26
+ else
27
+ {"linked" => service.linked.map(&:instance_id)}
28
+ end
19
29
  end
20
30
  end
21
31
  end
@@ -1,7 +1,7 @@
1
1
  module RubyHome
2
2
  module HTTP
3
3
  module UUIDHelper
4
- APPLE_BASE_UUID = -'0000-1000-8000-0026BB765291'
4
+ APPLE_BASE_UUID = -"0000-1000-8000-0026BB765291"
5
5
 
6
6
  def uuid_short_form(uuid)
7
7
  return uuid unless apple_defined_uuid?(uuid)
@@ -14,7 +14,7 @@ module RubyHome
14
14
  end
15
15
 
16
16
  def trim_leading_zeros(input)
17
- input.gsub(/^0*/, '')
17
+ input.gsub(/^0*/, "")
18
18
  end
19
19
  end
20
20
  end
@@ -16,21 +16,21 @@ module RubyHome
16
16
 
17
17
  def ==(other)
18
18
  self.class == other.class &&
19
- self.session == other.session &&
20
- self.characteristic == other.characteristic
19
+ session == other.session &&
20
+ characteristic == other.characteristic
21
21
  end
22
22
 
23
23
  attr_reader :session, :characteristic
24
24
 
25
25
  private
26
26
 
27
- def send_ev_response
28
- HAP::EVResponse.new(session, serialized_characteristic).send_response
29
- end
27
+ def send_ev_response
28
+ HAP::EVResponse.new(session, serialized_characteristic).send_response
29
+ end
30
30
 
31
- def serialized_characteristic
32
- HTTP::CharacteristicValueSerializer.new([characteristic]).serialized_json
33
- end
31
+ def serialized_characteristic
32
+ HTTP::CharacteristicValueSerializer.new([characteristic]).serialized_json
33
+ end
34
34
  end
35
35
  end
36
36
  end
@@ -1,16 +1,16 @@
1
1
  module RubyHome
2
2
  class StartSRPService
3
- def initialize(username: , password:)
3
+ def initialize(username:, password:)
4
4
  @username = username
5
5
  @password = password
6
6
  end
7
7
 
8
8
  def salt_bytes
9
- [salt].pack('H*')
9
+ [salt].pack("H*")
10
10
  end
11
11
 
12
12
  def public_key_bytes
13
- [public_key].pack('H*')
13
+ [public_key].pack("H*")
14
14
  end
15
15
 
16
16
  def proof
@@ -1,6 +1,6 @@
1
1
  module RubyHome
2
2
  class VerifyFinishService
3
- def initialize(accessory_info: , encrypted_data: , session_key:, shared_secret:)
3
+ def initialize(accessory_info:, encrypted_data:, session_key:, shared_secret:)
4
4
  @accessory_info = accessory_info
5
5
  @encrypted_data = encrypted_data
6
6
  @session_key = session_key
@@ -23,34 +23,34 @@ module RubyHome
23
23
 
24
24
  private
25
25
 
26
- NONCE = -'PV-Msg03'
26
+ NONCE = -"PV-Msg03"
27
27
 
28
- attr_reader :accessory_info, :encrypted_data, :session_key, :shared_secret
28
+ attr_reader :accessory_info, :encrypted_data, :session_key, :shared_secret
29
29
 
30
- def paired_client_exists?
31
- accessory_info.paired_clients.any? do |paired_client|
32
- paired_client[:identifier] == identifier
33
- end
30
+ def paired_client_exists?
31
+ accessory_info.paired_clients.any? do |paired_client|
32
+ paired_client[:identifier] == identifier
34
33
  end
34
+ end
35
35
 
36
- def chacha20poly1305
37
- HAP::Crypto::ChaCha20Poly1305.new(session_key)
38
- end
36
+ def chacha20poly1305
37
+ HAP::Crypto::ChaCha20Poly1305.new(session_key)
38
+ end
39
39
 
40
- def nonce
41
- HexHelper.pad(NONCE)
42
- end
40
+ def nonce
41
+ HexHelper.pad(NONCE)
42
+ end
43
43
 
44
- def decrypted_data
45
- chacha20poly1305.decrypt(nonce, encrypted_data)
46
- end
44
+ def decrypted_data
45
+ chacha20poly1305.decrypt(nonce, encrypted_data)
46
+ end
47
47
 
48
- def unpacked_decrypted_data
49
- TLV.decode(decrypted_data)
50
- end
48
+ def unpacked_decrypted_data
49
+ TLV.decode(decrypted_data)
50
+ end
51
51
 
52
- def identifier
53
- unpacked_decrypted_data[:identifier]
54
- end
52
+ def identifier
53
+ unpacked_decrypted_data[:identifier]
54
+ end
55
55
  end
56
56
  end
@@ -1,8 +1,8 @@
1
1
  module RubyHome
2
2
  class VerifySRPService
3
- def initialize(device_proof: , public_key: , srp_session: )
4
- @device_proof_bytes = device_proof.to_s.unpack1('H*')
5
- @public_key_bytes = public_key.to_s.unpack1('H*')
3
+ def initialize(device_proof:, public_key:, srp_session:)
4
+ @device_proof_bytes = device_proof.to_s.unpack1("H*")
5
+ @public_key_bytes = public_key.to_s.unpack1("H*")
6
6
  @srp_session = srp_session
7
7
  end
8
8
 
@@ -20,29 +20,29 @@ module RubyHome
20
20
 
21
21
  private
22
22
 
23
- def valid_session?
24
- !!verify_session
25
- end
23
+ def valid_session?
24
+ !!verify_session
25
+ end
26
26
 
27
- def session_key
28
- srp_verifier.K
29
- end
27
+ def session_key
28
+ srp_verifier.K
29
+ end
30
30
 
31
- def verify_session_bytes
32
- [verify_session].pack('H*')
33
- end
31
+ def verify_session_bytes
32
+ [verify_session].pack("H*")
33
+ end
34
34
 
35
- def verify_session
36
- srp_verifier.verify_session(
37
- srp_session.merge({A: public_key_bytes}),
38
- device_proof_bytes
39
- )
40
- end
35
+ def verify_session
36
+ srp_verifier.verify_session(
37
+ srp_session.merge({A: public_key_bytes}),
38
+ device_proof_bytes
39
+ )
40
+ end
41
41
 
42
- def srp_verifier
43
- @_verifier ||= RubyHome::SRP::Verifier.new
44
- end
42
+ def srp_verifier
43
+ @_verifier ||= RubyHome::SRP::Verifier.new
44
+ end
45
45
 
46
- attr_reader :public_key_bytes, :device_proof_bytes, :srp_session
46
+ attr_reader :public_key_bytes, :device_proof_bytes, :srp_session
47
47
  end
48
48
  end
@@ -1,10 +1,10 @@
1
- require_relative 'persistable'
1
+ require_relative "persistable"
2
2
 
3
3
  module RubyHome
4
4
  class IdentifierCache
5
5
  include Persistable
6
6
 
7
- self.source = 'identifier_cache.yml'
7
+ self.source = "identifier_cache.yml"
8
8
 
9
9
  def self.all
10
10
  raw_items = read || []
@@ -33,7 +33,7 @@ module RubyHome
33
33
  end
34
34
  end
35
35
 
36
- def initialize(accessory_id:, instance_id:, service_uuid: nil, subtype: , uuid: )
36
+ def initialize(accessory_id:, instance_id:, subtype:, uuid:, service_uuid: nil)
37
37
  @accessory_id = accessory_id
38
38
  @instance_id = instance_id
39
39
  @subtype = subtype
@@ -52,10 +52,9 @@ module RubyHome
52
52
  instance_id: identifier.instance_id,
53
53
  subtype: identifier.subtype,
54
54
  service_uuid: identifier.service_uuid,
55
- uuid: identifier.uuid,
55
+ uuid: identifier.uuid
56
56
  }
57
57
  end
58
58
  end
59
59
  end
60
60
  end
61
-
@@ -1,21 +1,21 @@
1
1
  module RubyHome
2
2
  module Password
3
3
  class << self
4
- DELIMITER = '-'
4
+ DELIMITER = "-"
5
5
  LENGTH = 8
6
6
  INVALIDS = [
7
- '00000000',
8
- '11111111',
9
- '22222222',
10
- '33333333',
11
- '44444444',
12
- '55555555',
13
- '66666666',
14
- '77777777',
15
- '88888888',
16
- '99999999',
17
- '12345678',
18
- '87654321',
7
+ "00000000",
8
+ "11111111",
9
+ "22222222",
10
+ "33333333",
11
+ "44444444",
12
+ "55555555",
13
+ "66666666",
14
+ "77777777",
15
+ "88888888",
16
+ "99999999",
17
+ "12345678",
18
+ "87654321"
19
19
  ]
20
20
 
21
21
  # The Setup Code must conform to the format XXX-XX-XXX where each X is a
@@ -34,7 +34,7 @@ module RubyHome
34
34
  [
35
35
  digits[0...3],
36
36
  digits[3...5],
37
- digits[5...8],
37
+ digits[5...8]
38
38
  ].join(DELIMITER)
39
39
  end
40
40