ruby_home 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests.yml +4 -4
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +2 -9
  5. data/.standard.yml +3 -0
  6. data/CHANGELOG.md +6 -1
  7. data/Gemfile +2 -2
  8. data/Rakefile +4 -4
  9. data/examples/air_purifier.rb +7 -8
  10. data/examples/air_quality_sensor.rb +8 -9
  11. data/examples/battery_service.rb +2 -3
  12. data/examples/carbon_dioxide_sensor.rb +2 -3
  13. data/examples/carbon_monoxide_sensor.rb +3 -4
  14. data/examples/contact_sensor.rb +2 -3
  15. data/examples/door.rb +5 -6
  16. data/examples/fan.rb +2 -3
  17. data/examples/fan_v2.rb +2 -3
  18. data/examples/garage_door_opener.rb +9 -10
  19. data/examples/heater_cooler.rb +9 -10
  20. data/examples/humidifier_dehumidifier.rb +9 -10
  21. data/examples/humidity_sensor.rb +2 -3
  22. data/examples/leak_sensor.rb +2 -3
  23. data/examples/light_sensor.rb +2 -3
  24. data/examples/lightbulb.rb +2 -3
  25. data/examples/lock_mechanism.rb +6 -7
  26. data/examples/motion_sensor.rb +2 -3
  27. data/examples/occupancy_sensor.rb +2 -3
  28. data/examples/outlet.rb +2 -3
  29. data/examples/security_system.rb +12 -13
  30. data/examples/smoke_sensor.rb +2 -3
  31. data/examples/switch.rb +2 -3
  32. data/examples/television.rb +8 -13
  33. data/examples/temperature_sensor.rb +2 -3
  34. data/examples/thermostat.rb +10 -11
  35. data/examples/window.rb +5 -6
  36. data/examples/window_covering.rb +5 -6
  37. data/lib/ruby_home.rb +21 -21
  38. data/lib/ruby_home/accessory.rb +1 -1
  39. data/lib/ruby_home/accessory_collection.rb +6 -6
  40. data/lib/ruby_home/accessory_info.rb +18 -18
  41. data/lib/ruby_home/characteristic.rb +8 -8
  42. data/lib/ruby_home/characteristic_collection.rb +13 -13
  43. data/lib/ruby_home/config/characteristics.yml +30 -635
  44. data/lib/ruby_home/config/manual_characteristics.yml +278 -0
  45. data/lib/ruby_home/config/manual_services.yml +45 -0
  46. data/lib/ruby_home/config/services.yml +329 -370
  47. data/lib/ruby_home/configuration.rb +4 -4
  48. data/lib/ruby_home/device_id.rb +3 -3
  49. data/lib/ruby_home/dns/service.rb +4 -6
  50. data/lib/ruby_home/dns/text_record.rb +9 -9
  51. data/lib/ruby_home/errors.rb +1 -0
  52. data/lib/ruby_home/factories/characteristic_factory.rb +37 -37
  53. data/lib/ruby_home/factories/service_factory.rb +72 -72
  54. data/lib/ruby_home/factories/templates/characteristic_template.rb +5 -5
  55. data/lib/ruby_home/factories/templates/service_template.rb +11 -10
  56. data/lib/ruby_home/hap/crypto/chacha20poly1305.rb +2 -2
  57. data/lib/ruby_home/hap/crypto/hkdf.rb +4 -4
  58. data/lib/ruby_home/hap/crypto/session_key.rb +7 -7
  59. data/lib/ruby_home/hap/decrypter.rb +8 -8
  60. data/lib/ruby_home/hap/encrypter.rb +5 -6
  61. data/lib/ruby_home/hap/ev_response.rb +17 -17
  62. data/lib/ruby_home/hap/hap_request.rb +1 -1
  63. data/lib/ruby_home/hap/server.rb +4 -4
  64. data/lib/ruby_home/hap/server_handler.rb +8 -10
  65. data/lib/ruby_home/hap/session.rb +22 -22
  66. data/lib/ruby_home/hap/values/base_value.rb +3 -3
  67. data/lib/ruby_home/hap/values/bool_value.rb +4 -4
  68. data/lib/ruby_home/hap/values/float_value.rb +4 -4
  69. data/lib/ruby_home/hap/values/identify_value.rb +1 -1
  70. data/lib/ruby_home/hap/values/int32_value.rb +4 -4
  71. data/lib/ruby_home/hap/values/null_value.rb +1 -1
  72. data/lib/ruby_home/hap/values/string_value.rb +11 -11
  73. data/lib/ruby_home/hap/values/uint32_value.rb +5 -5
  74. data/lib/ruby_home/hap/values/uint8_value.rb +14 -14
  75. data/lib/ruby_home/hex_helper.rb +3 -3
  76. data/lib/ruby_home/http/application.rb +7 -7
  77. data/lib/ruby_home/http/controllers/accessories_controller.rb +3 -3
  78. data/lib/ruby_home/http/controllers/application_controller.rb +6 -6
  79. data/lib/ruby_home/http/controllers/characteristics_controller.rb +29 -29
  80. data/lib/ruby_home/http/controllers/identify_controller.rb +10 -10
  81. data/lib/ruby_home/http/controllers/pair_setups_controller.rb +18 -18
  82. data/lib/ruby_home/http/controllers/pair_verifies_controller.rb +9 -9
  83. data/lib/ruby_home/http/controllers/pairings_controller.rb +5 -5
  84. data/lib/ruby_home/http/serializers/accessory_serializer.rb +5 -5
  85. data/lib/ruby_home/http/serializers/characteristic_serializer.rb +24 -24
  86. data/lib/ruby_home/http/serializers/characteristic_value_serializer.rb +5 -5
  87. data/lib/ruby_home/http/serializers/object_serializer.rb +1 -1
  88. data/lib/ruby_home/http/serializers/service_serializer.rb +9 -9
  89. data/lib/ruby_home/http/serializers/uuid_helper.rb +2 -2
  90. data/lib/ruby_home/http/services/session_notifier.rb +8 -8
  91. data/lib/ruby_home/http/services/start_srp_service.rb +3 -3
  92. data/lib/ruby_home/http/services/verify_finish_service.rb +22 -22
  93. data/lib/ruby_home/http/services/verify_srp_service.rb +22 -22
  94. data/lib/ruby_home/identifier_cache.rb +4 -5
  95. data/lib/ruby_home/password.rb +14 -14
  96. data/lib/ruby_home/persistable.rb +22 -7
  97. data/lib/ruby_home/service.rb +3 -3
  98. data/lib/ruby_home/service_collection.rb +1 -1
  99. data/lib/ruby_home/version.rb +1 -1
  100. data/rubyhome.gemspec +31 -31
  101. data/sbin/characteristic_generator.rb +22 -24
  102. data/sbin/service_generator.rb +36 -27
  103. metadata +25 -8
@@ -4,15 +4,15 @@ module RubyHome
4
4
  class Configuration
5
5
  extend Forwardable
6
6
 
7
- CATEGORIES_FILEPATH = (File.dirname(__FILE__) + '/config/categories.yml').freeze
7
+ CATEGORIES_FILEPATH = (File.dirname(__FILE__) + "/config/categories.yml").freeze
8
8
  CATEGORIES = YAML.load_file(CATEGORIES_FILEPATH).freeze
9
9
 
10
10
  def initialize(accessory_info = AccessoryInfo.instance)
11
11
  @accessory_info = accessory_info
12
12
  end
13
13
 
14
- DEFAULT_NAME = -'RubyHome'
15
- DEFAULT_HOST = -'0.0.0.0'
14
+ DEFAULT_NAME = -"RubyHome"
15
+ DEFAULT_HOST = -"0.0.0.0"
16
16
  DEFAULT_PORT = 4567
17
17
  DEFAULT_MODEL_NAME = DEFAULT_NAME
18
18
  DEFAULT_DISCOVERY_NAME = DEFAULT_NAME
@@ -40,7 +40,7 @@ module RubyHome
40
40
 
41
41
  def category_identifier=(value)
42
42
  if value.is_a?(Symbol)
43
- raise UnknownCategoriyIdentifierError if !CATEGORIES.include?(value)
43
+ raise UnknownCategoriyIdentifierError unless CATEGORIES.include?(value)
44
44
  @category_identifier = CATEGORIES[value]
45
45
  else
46
46
  @category_identifier = value.to_i
@@ -1,12 +1,12 @@
1
1
  module RubyHome
2
2
  module DeviceID
3
3
  class << self
4
- DELIMITER = ':'
4
+ DELIMITER = ":"
5
5
 
6
6
  # Device ID of the accessory must be a unique random number generated at every
7
7
  # factory reset and must persist across reboots
8
8
 
9
- def generate(digits=12)
9
+ def generate(digits = 12)
10
10
  random_hexadecimals(digits)
11
11
  .map(&:upcase)
12
12
  .each_slice(2)
@@ -18,7 +18,7 @@ module RubyHome
18
18
  rand(15).to_s(16)
19
19
  end
20
20
 
21
- def random_hexadecimals(digits=12)
21
+ def random_hexadecimals(digits = 12)
22
22
  digits
23
23
  .times
24
24
  .map { random_hexadecimal }
@@ -1,12 +1,12 @@
1
1
  module RubyHome
2
2
  module DNS
3
3
  class Service
4
- def initialize(configuration: )
4
+ def initialize(configuration:)
5
5
  @configuration = configuration
6
6
  end
7
7
 
8
8
  def update
9
- return if RbConfig::CONFIG['target_os'] =~ /linux/
9
+ return if /linux/.match?(RbConfig::CONFIG["target_os"])
10
10
 
11
11
  dnssd_service.add_record(DNSSD::Record::TXT, text_record.encode)
12
12
  end
@@ -20,9 +20,7 @@ module RubyHome
20
20
  attr_reader :configuration
21
21
 
22
22
  def dnssd_service
23
- @_dnssd_service ||= begin
24
- DNSSD::Service.register(name, type, nil, port, host, text_record)
25
- end
23
+ @_dnssd_service ||= DNSSD::Service.register(name, type, nil, port, host, text_record)
26
24
  end
27
25
 
28
26
  def name
@@ -30,7 +28,7 @@ module RubyHome
30
28
  end
31
29
 
32
30
  def type
33
- -'_hap._tcp'
31
+ -"_hap._tcp"
34
32
  end
35
33
 
36
34
  def port
@@ -12,14 +12,14 @@ module RubyHome
12
12
 
13
13
  def to_hash
14
14
  {
15
- 'c#' => current_configuration_number,
16
- 'ci' => accessory_category_identifier,
17
- 'ff' => feature_flags,
18
- 'id' => device_id,
19
- 'md' => model_name,
20
- 'pv' => protocol_version,
21
- 's#' => current_state_number,
22
- 'sf' => status_flags
15
+ "c#" => current_configuration_number,
16
+ "ci" => accessory_category_identifier,
17
+ "ff" => feature_flags,
18
+ "id" => device_id,
19
+ "md" => model_name,
20
+ "pv" => protocol_version,
21
+ "s#" => current_state_number,
22
+ "sf" => status_flags
23
23
  }
24
24
  end
25
25
 
@@ -52,7 +52,7 @@ module RubyHome
52
52
 
53
53
  STATUS_FLAGS = {
54
54
  PAIRED: 0,
55
- NOT_PAIRED: 1,
55
+ NOT_PAIRED: 1
56
56
  }.freeze
57
57
 
58
58
  def status_flags
@@ -1,4 +1,5 @@
1
1
  module RubyHome
2
2
  class RubyHomeError < StandardError; end
3
+
3
4
  class UnknownValueError < RubyHomeError; end
4
5
  end
@@ -1,6 +1,6 @@
1
1
  module RubyHome
2
2
  class CharacteristicFactory
3
- def self.create(characteristic_name, service: , subtype: 'default' , value: nil)
3
+ def self.create(characteristic_name, service:, subtype: "default", value: nil)
4
4
  new(
5
5
  characteristic_name: characteristic_name,
6
6
  service: service,
@@ -36,48 +36,48 @@ module RubyHome
36
36
 
37
37
  private
38
38
 
39
- def initialize(characteristic_name:, service:, subtype:, value:)
40
- @characteristic_name = characteristic_name.to_sym
41
- @service = service
42
- @subtype = subtype
43
- @requested_value = value
44
- end
39
+ def initialize(characteristic_name:, service:, subtype:, value:)
40
+ @characteristic_name = characteristic_name.to_sym
41
+ @service = service
42
+ @subtype = subtype
43
+ @requested_value = value
44
+ end
45
45
 
46
- attr_reader :service, :characteristic_name, :subtype
46
+ attr_reader :service, :characteristic_name, :subtype
47
47
 
48
- def accessory
49
- service.accessory
50
- end
48
+ def accessory
49
+ service.accessory
50
+ end
51
51
 
52
- def template
53
- @template ||= CharacteristicTemplate.find_by(name: characteristic_name)
54
- end
52
+ def template
53
+ @template ||= CharacteristicTemplate.find_by(name: characteristic_name)
54
+ end
55
55
 
56
- def value_object
57
- value_object_class.new(template, @requested_value)
58
- end
56
+ def value_object
57
+ value_object_class.new(template, @requested_value)
58
+ end
59
59
 
60
- def value_object_class
61
- BaseValue.value_for_template(template)
62
- end
60
+ def value_object_class
61
+ BaseValue.value_for_template(template)
62
+ end
63
63
 
64
- def persisted_characteristic
65
- IdentifierCache.find_by(
66
- accessory_id: service.accessory_id,
67
- service_uuid: service.uuid,
68
- uuid: template.uuid,
69
- subtype: subtype
70
- )
71
- end
64
+ def persisted_characteristic
65
+ IdentifierCache.find_by(
66
+ accessory_id: service.accessory_id,
67
+ service_uuid: service.uuid,
68
+ uuid: template.uuid,
69
+ subtype: subtype
70
+ )
71
+ end
72
72
 
73
- def persist_characteristic(characteristic)
74
- IdentifierCache.create(
75
- accessory_id: characteristic.accessory_id,
76
- instance_id: characteristic.instance_id,
77
- service_uuid: service.uuid,
78
- uuid: characteristic.uuid,
79
- subtype: subtype
80
- )
81
- end
73
+ def persist_characteristic(characteristic)
74
+ IdentifierCache.create(
75
+ accessory_id: characteristic.accessory_id,
76
+ instance_id: characteristic.instance_id,
77
+ service_uuid: service.uuid,
78
+ uuid: characteristic.uuid,
79
+ subtype: subtype
80
+ )
81
+ end
82
82
  end
83
83
  end
@@ -1,6 +1,6 @@
1
1
  module RubyHome
2
2
  class ServiceFactory
3
- def self.create(service_name, accessory: Accessory.new, subtype: 'default', **options)
3
+ def self.create(service_name, accessory: Accessory.new, subtype: "default", **options)
4
4
  new(
5
5
  service_name: service_name,
6
6
  accessory: accessory,
@@ -14,7 +14,7 @@ module RubyHome
14
14
  accessory: accessory,
15
15
  description: template.description,
16
16
  name: service_name,
17
- uuid: template.uuid,
17
+ uuid: template.uuid
18
18
  )
19
19
 
20
20
  if persisted_service
@@ -38,87 +38,87 @@ module RubyHome
38
38
 
39
39
  private
40
40
 
41
- ACCESSORY_INFORMATION_OPTIONS = [
42
- :firmware_revision,
43
- :manufacturer,
44
- :model,
45
- :name,
46
- :serial_number
47
- ].freeze
48
-
49
- def initialize(service_name:, accessory:, subtype:, **options)
50
- @service_name = service_name.to_sym
51
- @accessory = accessory
52
- @subtype = subtype
53
- @options = options
54
- end
41
+ ACCESSORY_INFORMATION_OPTIONS = [
42
+ :firmware_revision,
43
+ :manufacturer,
44
+ :model,
45
+ :name,
46
+ :serial_number
47
+ ].freeze
48
+
49
+ def initialize(service_name:, accessory:, subtype:, **options)
50
+ @service_name = service_name.to_sym
51
+ @accessory = accessory
52
+ @subtype = subtype
53
+ @options = options
54
+ end
55
55
 
56
- attr_reader :service_name, :accessory, :subtype, :options
57
-
58
- def create_required_characteristics(service)
59
- template.required_characteristics.each do |characteristic_template|
60
- characteristic_name = characteristic_template.name
61
- CharacteristicFactory.create(
62
- characteristic_template.name,
63
- service: service,
64
- subtype: subtype,
65
- value: options[characteristic_name]
66
- )
67
- end
68
- end
56
+ attr_reader :service_name, :accessory, :subtype, :options
69
57
 
70
- def create_optional_characteristics(service)
71
- optional_characteristic_templates.each do |characteristic_template|
72
- characteristic_name = characteristic_template.name
73
- CharacteristicFactory.create(
74
- characteristic_name,
75
- service: service,
76
- subtype: subtype,
77
- value: options[characteristic_name]
78
- )
79
- end
58
+ def create_required_characteristics(service)
59
+ template.required_characteristics.each do |characteristic_template|
60
+ characteristic_name = characteristic_template.name
61
+ CharacteristicFactory.create(
62
+ characteristic_template.name,
63
+ service: service,
64
+ subtype: subtype,
65
+ value: options[characteristic_name]
66
+ )
80
67
  end
68
+ end
81
69
 
82
- def optional_characteristic_templates
83
- template.optional_characteristics.select do |characteristic_template|
84
- options.keys.include?(characteristic_template.name)
85
- end
70
+ def create_optional_characteristics(service)
71
+ optional_characteristic_templates.each do |characteristic_template|
72
+ characteristic_name = characteristic_template.name
73
+ CharacteristicFactory.create(
74
+ characteristic_name,
75
+ service: service,
76
+ subtype: subtype,
77
+ value: options[characteristic_name]
78
+ )
86
79
  end
80
+ end
87
81
 
88
- def accessory_information_factory?
89
- service_name == :accessory_information
82
+ def optional_characteristic_templates
83
+ template.optional_characteristics.select do |characteristic_template|
84
+ options.key?(characteristic_template.name)
90
85
  end
86
+ end
91
87
 
92
- def create_accessory_information
93
- return if accessory.has_accessory_information?
88
+ def accessory_information_factory?
89
+ service_name == :accessory_information
90
+ end
94
91
 
95
- ServiceFactory.create(
96
- :accessory_information,
97
- accessory: accessory,
98
- subtype: 'accessory_information',
99
- **options.slice(*ACCESSORY_INFORMATION_OPTIONS)
100
- )
101
- end
92
+ def create_accessory_information
93
+ return if accessory.has_accessory_information?
102
94
 
103
- def template
104
- @template ||= ServiceTemplate.find_by(name: service_name)
105
- end
95
+ ServiceFactory.create(
96
+ :accessory_information,
97
+ accessory: accessory,
98
+ subtype: "accessory_information",
99
+ **options.slice(*ACCESSORY_INFORMATION_OPTIONS)
100
+ )
101
+ end
106
102
 
107
- def persisted_service
108
- IdentifierCache.find_by(
109
- accessory_id: accessory.id,
110
- uuid: template.uuid,
111
- subtype: subtype
112
- )
113
- end
103
+ def template
104
+ @template ||= ServiceTemplate.find_by(name: service_name)
105
+ end
114
106
 
115
- def persist_service(service)
116
- IdentifierCache.create(
117
- accessory_id: accessory.id,
118
- instance_id: service.instance_id,
119
- uuid: template.uuid,
120
- subtype: subtype
121
- )
122
- end
107
+ def persisted_service
108
+ IdentifierCache.find_by(
109
+ accessory_id: accessory.id,
110
+ uuid: template.uuid,
111
+ subtype: subtype
112
+ )
113
+ end
114
+
115
+ def persist_service(service)
116
+ IdentifierCache.create(
117
+ accessory_id: accessory.id,
118
+ instance_id: service.instance_id,
119
+ uuid: template.uuid,
120
+ subtype: subtype
121
+ )
122
+ end
123
123
  end
124
124
  end
@@ -1,7 +1,8 @@
1
1
  module RubyHome
2
2
  class CharacteristicTemplate
3
- FILEPATH = (File.dirname(__FILE__) + '/../../config/characteristics.yml').freeze
4
- DATA = YAML.load_file(FILEPATH).freeze
3
+ FILENAMES = %w[characteristics.yml manual_characteristics.yml].freeze
4
+ FILEPATHS = FILENAMES.map { |filename| File.join(__dir__, "..", "..", "config", filename) }.freeze
5
+ DATA = FILEPATHS.flat_map { |filepath| YAML.load_file(filepath) }.freeze
5
6
 
6
7
  def self.all
7
8
  @@all ||= DATA.map { |data| new(**data) }
@@ -15,18 +16,17 @@ module RubyHome
15
16
  end
16
17
  end
17
18
 
18
- def initialize(name:, description:, uuid:, format:, unit:, permissions:, properties:, constraints: )
19
+ def initialize(name:, description:, uuid:, format:, unit:, properties:, constraints:)
19
20
  @name = name
20
21
  @description = description
21
22
  @uuid = uuid
22
23
  @format = format
23
24
  @unit = unit
24
- @permissions = permissions
25
25
  @properties = properties
26
26
  @constraints = constraints
27
27
  end
28
28
 
29
- attr_reader :name, :description, :uuid, :format, :unit, :permissions, :properties
29
+ attr_reader :name, :description, :uuid, :format, :unit, :properties
30
30
 
31
31
  def constraints
32
32
  @constraints || {}
@@ -1,7 +1,8 @@
1
1
  module RubyHome
2
2
  class ServiceTemplate
3
- FILEPATH = (File.dirname(__FILE__) + '/../../config/services.yml').freeze
4
- DATA = YAML.load_file(FILEPATH).freeze
3
+ FILENAMES = %w[services.yml manual_services.yml].freeze
4
+ FILEPATHS = FILENAMES.map { |filename| File.join(__dir__, "..", "..", "config", filename) }.freeze
5
+ DATA = FILEPATHS.flat_map { |filepath| YAML.load_file(filepath) }.freeze
5
6
 
6
7
  def self.all
7
8
  @all ||= DATA.map { |data| new(**data) }
@@ -15,25 +16,25 @@ module RubyHome
15
16
  end
16
17
  end
17
18
 
18
- def initialize(name:, description:, uuid:, optional_characteristics_uuids:, required_characteristics_uuids:)
19
+ def initialize(name:, description:, uuid:, optional_characteristic_names:, required_characteristic_names:)
19
20
  @name = name
20
21
  @description = description
21
22
  @uuid = uuid
22
- @optional_characteristics_uuids = optional_characteristics_uuids
23
- @required_characteristics_uuids = required_characteristics_uuids
23
+ @optional_characteristic_names = optional_characteristic_names
24
+ @required_characteristic_names = required_characteristic_names
24
25
  end
25
26
 
26
- attr_reader :name, :description, :uuid, :optional_characteristics_uuids, :required_characteristics_uuids
27
+ attr_reader :name, :description, :uuid, :optional_characteristic_names, :required_characteristic_names
27
28
 
28
29
  def optional_characteristics
29
- @optional_characteristics ||= optional_characteristics_uuids.map do |uuid|
30
- CharacteristicTemplate.find_by(uuid: uuid)
30
+ @optional_characteristics ||= optional_characteristic_names.map do |name|
31
+ CharacteristicTemplate.find_by(name: name)
31
32
  end
32
33
  end
33
34
 
34
35
  def required_characteristics
35
- @required_characteristics ||= required_characteristics_uuids.map do |uuid|
36
- CharacteristicTemplate.find_by(uuid: uuid)
36
+ @required_characteristics ||= required_characteristic_names.map do |name|
37
+ CharacteristicTemplate.find_by(name: name)
37
38
  end
38
39
  end
39
40
  end