ruby_home 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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