ruby_home 0.1.5 → 0.1.7
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.
- checksums.yaml +4 -4
- data/README.md +64 -5
- data/bin/rubyhome +4 -4
- data/lib/ruby_home/accessory_info.rb +45 -30
- data/lib/ruby_home/factories/characteristic_factory.rb +27 -19
- data/lib/ruby_home/factories/default_values/float_value.rb +1 -1
- data/lib/ruby_home/factories/service_factory.rb +89 -0
- data/lib/ruby_home/factories/templates/characteristic_template.rb +6 -2
- data/lib/ruby_home/hap/accessory.rb +24 -3
- data/lib/ruby_home/hap/accessory_collection.rb +38 -0
- data/lib/ruby_home/hap/characteristic.rb +25 -19
- data/lib/ruby_home/hap/crypto/session_key.rb +31 -0
- data/lib/ruby_home/hap/ev_response.rb +64 -0
- data/lib/ruby_home/{http → hap}/hap_request.rb +12 -5
- data/lib/ruby_home/{http → hap}/hap_response.rb +7 -4
- data/lib/ruby_home/hap/server.rb +81 -0
- data/lib/ruby_home/hap/service.rb +11 -15
- data/lib/ruby_home/http/application.rb +17 -22
- data/lib/ruby_home/http/controllers/application_controller.rb +8 -4
- data/lib/ruby_home/http/controllers/characteristics_controller.rb +19 -4
- data/lib/ruby_home/http/controllers/pair_verifies_controller.rb +3 -5
- data/lib/ruby_home/http/serializers/object_serializer.rb +1 -1
- data/lib/ruby_home/http/services/socket_notifier.rb +40 -0
- data/lib/ruby_home/http/services/start_srp_service.rb +36 -34
- data/lib/ruby_home/http/services/verify_srp_service.rb +55 -53
- data/lib/ruby_home/identifier_cache.rb +22 -49
- data/lib/ruby_home/persistable.rb +36 -0
- data/lib/ruby_home/version.rb +1 -1
- data/lib/ruby_home.rb +14 -5
- data/rubyhome.gemspec +3 -3
- metadata +35 -38
- data/lib/ruby_home/factories/accessory_factory.rb +0 -73
- data/lib/ruby_home/http/hap_server.rb +0 -60
- data/lib/ruby_home/rack/handler/hap_server.rb +0 -21
- data/lib/ruby_home/yaml_record.rb +0 -440
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7f5f53b947e2cfbce79204572dd8d29b284c5434304aee7214b6a7a33d3e0a6
|
4
|
+
data.tar.gz: '086845819574df45f838c8ff67979f55f01763b6fe44114af76fd3479f8f1b83'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 419df1283d71010c0a4e8e89f60f01fa752ea9366f6fe59a1ca3a2e202a9ab72361ed4dff5389ecdfb8b084feb40cd0d5c62fcbf16b90b65bfcd5096c7a3a4ab
|
7
|
+
data.tar.gz: 3644d107b711edadd639f881614ebd85cb8e164cbeebf5db30e1748303983b52bf056371e952a6c9c0e39aa2a7744351549ddaf2eef4c655428dabdf0c9fe2eb
|
data/README.md
CHANGED
@@ -21,18 +21,18 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
$ gem install ruby_home
|
23
23
|
|
24
|
-
## Usage
|
24
|
+
## Basic Usage
|
25
25
|
|
26
26
|
Create a fan with an on/off switch.
|
27
27
|
|
28
28
|
```ruby
|
29
29
|
require 'ruby_home'
|
30
30
|
|
31
|
-
accessory_information = RubyHome::
|
32
|
-
fan = RubyHome::
|
31
|
+
accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
|
32
|
+
fan = RubyHome::ServiceFactory.create(:fan)
|
33
33
|
|
34
|
-
fan.characteristic(:on).
|
35
|
-
if
|
34
|
+
fan.characteristic(:on).after_update do |characteristic|
|
35
|
+
if characteristic.value == 1
|
36
36
|
puts "Fan switched on"
|
37
37
|
else
|
38
38
|
puts "Fan switched off"
|
@@ -42,6 +42,65 @@ end
|
|
42
42
|
RubyHome.run
|
43
43
|
```
|
44
44
|
|
45
|
+
Create a garage door opener.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'ruby_home'
|
49
|
+
|
50
|
+
accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
|
51
|
+
door = RubyHome::ServiceFactory.create(:garage_door_opener)
|
52
|
+
|
53
|
+
door.characteristic(:target_door_state).after_update do |characteristic|
|
54
|
+
if characteristic.value == 0 # open
|
55
|
+
sleep 1
|
56
|
+
door.characteristic(:current_door_state).value = 0
|
57
|
+
elsif characteristic.value == 1 #closed
|
58
|
+
sleep 1
|
59
|
+
door.characteristic(:current_door_state).value = 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
RubyHome.run
|
64
|
+
```
|
65
|
+
|
66
|
+
## Customization
|
67
|
+
|
68
|
+
RubyHome ties to provide sane defaults for all services. Customization of any of the options is possible.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
require 'ruby_home'
|
72
|
+
|
73
|
+
accessory_information = RubyHome::ServiceFactory.create(:accessory_information,
|
74
|
+
firmware_revision: '4.3.18421',
|
75
|
+
manufacturer: 'Fake Company',
|
76
|
+
model: 'BSB001',
|
77
|
+
name: 'Kickass fan bridge',
|
78
|
+
serial_number: 'AB1-UK-A123456'
|
79
|
+
)
|
80
|
+
|
81
|
+
fan = RubyHome::ServiceFactory.create(:fan,
|
82
|
+
on: false,
|
83
|
+
rotation_speed: 50,
|
84
|
+
rotation_direction: 1,
|
85
|
+
firmware_revision: '105.0.21169',
|
86
|
+
manufacturer: 'Fake Company',
|
87
|
+
model: 'LWB006',
|
88
|
+
name: 'Kickass fan',
|
89
|
+
serial_number: '123-UK-A12345'
|
90
|
+
)
|
91
|
+
|
92
|
+
fan.characteristic(:on).after_update do |characteristic|
|
93
|
+
if characteristic.value == 1
|
94
|
+
puts "Fan switched on"
|
95
|
+
else
|
96
|
+
puts "Fan switched off"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
RubyHome.run
|
101
|
+
```
|
102
|
+
|
103
|
+
|
45
104
|
## Development
|
46
105
|
|
47
106
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/rubyhome
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
require_relative '../lib/ruby_home'
|
4
4
|
|
5
|
-
accessory_information = RubyHome::
|
6
|
-
fan = RubyHome::
|
5
|
+
accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
|
6
|
+
fan = RubyHome::ServiceFactory.create(:fan)
|
7
7
|
|
8
|
-
fan.characteristic(:on).
|
9
|
-
if
|
8
|
+
fan.characteristic(:on).after_update do |characteristic|
|
9
|
+
if characteristic.value == 1
|
10
10
|
puts "Fan switched on"
|
11
11
|
else
|
12
12
|
puts "Fan switched off"
|
@@ -1,24 +1,46 @@
|
|
1
|
-
require_relative '
|
2
|
-
require_relative 'yaml_record'
|
1
|
+
require_relative 'persistable'
|
3
2
|
|
4
3
|
module RubyHome
|
5
|
-
class AccessoryInfo
|
4
|
+
class AccessoryInfo
|
5
|
+
include Persistable
|
6
|
+
|
7
|
+
self.source = 'accessory_info.yml'
|
8
|
+
|
9
|
+
def self.instance
|
10
|
+
@@_instance ||= persisted || create
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.reload
|
14
|
+
@@_instance = nil
|
15
|
+
end
|
16
|
+
|
6
17
|
USERNAME = -'Pair-Setup'
|
7
18
|
|
8
|
-
|
9
|
-
|
19
|
+
def initialize(device_id: nil, paired_clients: [], password: nil, signature_key: nil)
|
20
|
+
@device_id = device_id
|
21
|
+
@paired_clients = paired_clients
|
22
|
+
@password = password
|
23
|
+
@signature_key = signature_key
|
24
|
+
end
|
10
25
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
set_callback :before_create, :set_signature_key
|
26
|
+
def username
|
27
|
+
USERNAME
|
28
|
+
end
|
15
29
|
|
16
|
-
def
|
17
|
-
|
30
|
+
def password
|
31
|
+
@password ||= Password.generate
|
32
|
+
end
|
33
|
+
|
34
|
+
def device_id
|
35
|
+
@device_id ||= DeviceID.generate
|
36
|
+
end
|
37
|
+
|
38
|
+
def paired_clients
|
39
|
+
@paired_clients ||= []
|
18
40
|
end
|
19
41
|
|
20
42
|
def add_paired_client(admin: false, identifier: , public_key: )
|
21
|
-
paired_clients << { admin: admin, identifier: identifier, public_key: public_key }
|
43
|
+
@paired_clients << { admin: admin, identifier: identifier, public_key: public_key }
|
22
44
|
save
|
23
45
|
end
|
24
46
|
|
@@ -35,26 +57,19 @@ module RubyHome
|
|
35
57
|
@signing_key ||= RbNaCl::Signatures::Ed25519::SigningKey.new([signature_key].pack('H*'))
|
36
58
|
end
|
37
59
|
|
38
|
-
def username
|
39
|
-
USERNAME
|
40
|
-
end
|
41
|
-
|
42
60
|
private
|
43
61
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def set_paired_clients
|
49
|
-
self.paired_clients = []
|
50
|
-
end
|
62
|
+
def signature_key
|
63
|
+
@signature_key ||= RbNaCl::Signatures::Ed25519::SigningKey.generate.to_bytes.unpack1('H*')
|
64
|
+
end
|
51
65
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
66
|
+
def persisted_attributes
|
67
|
+
{
|
68
|
+
device_id: device_id,
|
69
|
+
paired_clients: paired_clients,
|
70
|
+
password: password,
|
71
|
+
signature_key: signature_key
|
72
|
+
}
|
73
|
+
end
|
59
74
|
end
|
60
75
|
end
|
@@ -4,37 +4,45 @@ module RubyHome
|
|
4
4
|
identify: nil,
|
5
5
|
}.freeze
|
6
6
|
|
7
|
-
def self.create(characteristic_name,
|
8
|
-
new(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@options = options
|
7
|
+
def self.create(characteristic_name, service: , value: nil)
|
8
|
+
new(
|
9
|
+
characteristic_name: characteristic_name,
|
10
|
+
service: service,
|
11
|
+
value: value
|
12
|
+
).create
|
14
13
|
end
|
15
14
|
|
16
15
|
def create
|
17
|
-
|
16
|
+
service.characteristics << new_characteristic
|
18
17
|
|
19
|
-
|
20
|
-
characteristic
|
18
|
+
new_characteristic
|
21
19
|
end
|
22
20
|
|
23
21
|
private
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@
|
23
|
+
def initialize(characteristic_name:, service:, value:)
|
24
|
+
@characteristic_name = characteristic_name.to_sym
|
25
|
+
@service = service
|
26
|
+
@value = value || default_value
|
29
27
|
end
|
30
28
|
|
31
|
-
|
32
|
-
|
29
|
+
attr_reader :service, :characteristic_name, :value
|
30
|
+
|
31
|
+
def new_characteristic
|
32
|
+
@new_characteristic ||= Characteristic.new(
|
33
|
+
description: template.description,
|
34
|
+
format: template.format,
|
35
|
+
name: characteristic_name,
|
36
|
+
properties: template.properties,
|
37
|
+
service: service,
|
38
|
+
unit: template.unit,
|
39
|
+
uuid: template.uuid,
|
40
|
+
value: value
|
41
|
+
)
|
33
42
|
end
|
34
43
|
|
35
|
-
def
|
36
|
-
|
37
|
-
options.merge(template.to_hash)
|
44
|
+
def template
|
45
|
+
@template ||= CharacteristicTemplate.find_by(name: characteristic_name)
|
38
46
|
end
|
39
47
|
|
40
48
|
def default_value
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module RubyHome
|
2
|
+
class ServiceFactory
|
3
|
+
def self.create(service_name, accessory: Accessory.new, **options)
|
4
|
+
new(
|
5
|
+
service_name: service_name,
|
6
|
+
accessory: accessory,
|
7
|
+
**options
|
8
|
+
).create
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
accessory.services << new_service
|
13
|
+
|
14
|
+
create_accessory_information
|
15
|
+
create_required_characteristics
|
16
|
+
create_optional_characteristics
|
17
|
+
|
18
|
+
new_service
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
ACCESSORY_INFORMATION_OPTIONS = [
|
23
|
+
:firmware_revision,
|
24
|
+
:manufacturer,
|
25
|
+
:model,
|
26
|
+
:name,
|
27
|
+
:serial_number
|
28
|
+
].freeze
|
29
|
+
|
30
|
+
def initialize(service_name:, accessory:, **options)
|
31
|
+
@service_name = service_name.to_sym
|
32
|
+
@accessory = accessory
|
33
|
+
@options = options
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :service_name, :accessory, :options
|
37
|
+
|
38
|
+
def new_service
|
39
|
+
@new_service ||= Service.new(
|
40
|
+
accessory: accessory,
|
41
|
+
description: template.description,
|
42
|
+
name: service_name,
|
43
|
+
uuid: template.uuid
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_required_characteristics
|
48
|
+
template.required_characteristics.each do |characteristic_template|
|
49
|
+
characteristic_name = characteristic_template.name
|
50
|
+
CharacteristicFactory.create(
|
51
|
+
characteristic_template.name,
|
52
|
+
service: new_service,
|
53
|
+
value: options[characteristic_name]
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_optional_characteristics
|
59
|
+
optional_characteristic_templates.each do |characteristic_template|
|
60
|
+
characteristic_name = characteristic_template.name
|
61
|
+
CharacteristicFactory.create(
|
62
|
+
characteristic_name,
|
63
|
+
service: new_service,
|
64
|
+
value: options[characteristic_name]
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def optional_characteristic_templates
|
70
|
+
template.optional_characteristics.select do |characteristic_template|
|
71
|
+
options.keys.include?(characteristic_template.name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_accessory_information
|
76
|
+
unless service_name == :accessory_information
|
77
|
+
ServiceFactory.create(
|
78
|
+
:accessory_information,
|
79
|
+
accessory: accessory,
|
80
|
+
**options.slice(*ACCESSORY_INFORMATION_OPTIONS)
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def template
|
86
|
+
@template ||= ServiceTemplate.find_by(name: service_name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -15,7 +15,7 @@ module RubyHome
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def initialize(name:, description:, uuid:, format:, unit:, permissions:, properties:, constraints:)
|
18
|
+
def initialize(name:, description:, uuid:, format:, unit:, permissions:, properties:, constraints: )
|
19
19
|
@name = name
|
20
20
|
@description = description
|
21
21
|
@uuid = uuid
|
@@ -26,7 +26,11 @@ module RubyHome
|
|
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, :permissions, :properties
|
30
|
+
|
31
|
+
def constraints
|
32
|
+
@constraints || {}
|
33
|
+
end
|
30
34
|
|
31
35
|
def to_hash
|
32
36
|
{
|
@@ -1,11 +1,22 @@
|
|
1
1
|
module RubyHome
|
2
2
|
class Accessory
|
3
|
+
@@all = AccessoryCollection.new
|
4
|
+
|
5
|
+
def self.all
|
6
|
+
@@all
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.reset
|
10
|
+
@@all = AccessoryCollection.new
|
11
|
+
end
|
12
|
+
|
3
13
|
def initialize
|
4
14
|
@services = []
|
15
|
+
@id = next_available_accessory_id
|
16
|
+
@@all << self
|
5
17
|
end
|
6
18
|
|
7
|
-
|
8
|
-
attr_reader :services
|
19
|
+
attr_reader :services, :id
|
9
20
|
|
10
21
|
def characteristics
|
11
22
|
services.flat_map(&:characteristics)
|
@@ -15,12 +26,22 @@ module RubyHome
|
|
15
26
|
(largest_instance_id || 0) + 1
|
16
27
|
end
|
17
28
|
|
29
|
+
private
|
30
|
+
|
18
31
|
def instance_ids
|
19
|
-
|
32
|
+
instances.map(&:instance_id)
|
33
|
+
end
|
34
|
+
|
35
|
+
def instances
|
36
|
+
services + characteristics
|
20
37
|
end
|
21
38
|
|
22
39
|
def largest_instance_id
|
23
40
|
instance_ids.max
|
24
41
|
end
|
42
|
+
|
43
|
+
def next_available_accessory_id
|
44
|
+
self.class.all.count + 1
|
45
|
+
end
|
25
46
|
end
|
26
47
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RubyHome
|
2
|
+
class AccessoryCollection
|
3
|
+
include Enumerable
|
4
|
+
attr_accessor :accessories
|
5
|
+
|
6
|
+
def initialize(*accessories)
|
7
|
+
@accessories = accessories
|
8
|
+
end
|
9
|
+
|
10
|
+
def each
|
11
|
+
@accessories.map do |accessory|
|
12
|
+
yield accessory
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(accessory)
|
17
|
+
@accessories << accessory
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_characteristic(attributes)
|
21
|
+
characteristics.find do |characteristic|
|
22
|
+
attributes.all? do |key, value|
|
23
|
+
characteristic.send(key) == value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def services
|
31
|
+
accessories.flat_map(&:services)
|
32
|
+
end
|
33
|
+
|
34
|
+
def characteristics
|
35
|
+
services.flat_map(&:characteristics)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -2,6 +2,18 @@ module RubyHome
|
|
2
2
|
class Characteristic
|
3
3
|
include Wisper::Publisher
|
4
4
|
|
5
|
+
public :local_registrations
|
6
|
+
|
7
|
+
def unsubscribe(*listeners)
|
8
|
+
local_registrations.delete_if do |registration|
|
9
|
+
listeners.include?(registration.listener)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def after_update(&block)
|
14
|
+
on(:after_update, &block)
|
15
|
+
end
|
16
|
+
|
5
17
|
PROPERTIES = {
|
6
18
|
'cnotify' => 'ev',
|
7
19
|
'read' => 'pr',
|
@@ -18,10 +30,20 @@ module RubyHome
|
|
18
30
|
@properties = properties
|
19
31
|
@service = service
|
20
32
|
@value = value
|
33
|
+
@instance_id = accessory.next_available_instance_id
|
21
34
|
end
|
22
35
|
|
23
|
-
attr_reader
|
24
|
-
|
36
|
+
attr_reader(
|
37
|
+
:service,
|
38
|
+
:value,
|
39
|
+
:uuid,
|
40
|
+
:name,
|
41
|
+
:description,
|
42
|
+
:format,
|
43
|
+
:unit,
|
44
|
+
:properties,
|
45
|
+
:instance_id
|
46
|
+
)
|
25
47
|
|
26
48
|
def accessory
|
27
49
|
service.accessory
|
@@ -37,24 +59,8 @@ module RubyHome
|
|
37
59
|
|
38
60
|
def value=(new_value)
|
39
61
|
return if name == :identify
|
40
|
-
|
41
62
|
@value = new_value
|
42
|
-
broadcast(:
|
43
|
-
end
|
44
|
-
|
45
|
-
def inspect
|
46
|
-
{
|
47
|
-
name: name,
|
48
|
-
value: value,
|
49
|
-
accessory_id: accessory_id,
|
50
|
-
service_iid: service_iid,
|
51
|
-
instance_id: instance_id
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
def save
|
56
|
-
IdentifierCache.add_accessory(accessory)
|
57
|
-
IdentifierCache.add_characteristic(self)
|
63
|
+
broadcast(:after_update, self)
|
58
64
|
end
|
59
65
|
end
|
60
66
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RubyHome
|
2
|
+
module HAP
|
3
|
+
module Crypto
|
4
|
+
class SessionKey
|
5
|
+
def initialize(shared_secret)
|
6
|
+
@shared_secret = shared_secret
|
7
|
+
end
|
8
|
+
|
9
|
+
def controller_to_accessory_key
|
10
|
+
@controller_to_accessory_key ||= generate_shared_secret_key(WRITE)
|
11
|
+
end
|
12
|
+
|
13
|
+
def accessory_to_controller_key
|
14
|
+
@accessory_to_controller_key ||= generate_shared_secret_key(READ)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
SALT = -'Control-Salt'
|
20
|
+
READ = -'Control-Read-Encryption-Key'
|
21
|
+
WRITE = -'Control-Write-Encryption-Key'
|
22
|
+
|
23
|
+
attr_reader :shared_secret
|
24
|
+
|
25
|
+
def generate_shared_secret_key(info)
|
26
|
+
Crypto::HKDF.new(info: info, salt: SALT).encrypt(shared_secret)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RubyHome
|
2
|
+
module HAP
|
3
|
+
class EVResponse
|
4
|
+
def initialize(socket, body)
|
5
|
+
@socket = socket
|
6
|
+
@body = body
|
7
|
+
cache[:accessory_to_controller_count] ||= 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_response
|
11
|
+
response = ''
|
12
|
+
|
13
|
+
send_header(response)
|
14
|
+
send_body(response)
|
15
|
+
|
16
|
+
encrypted_response = encrypter.encrypt(response).join
|
17
|
+
cache[:accessory_to_controller_count] = encrypter.count
|
18
|
+
|
19
|
+
socket << encrypted_response
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
CRLF = -"\x0d\x0a"
|
25
|
+
STATUS_LINE = -'EVENT/1.0 200 OK'
|
26
|
+
CONTENT_TYPE_LINE = -'Content-Type: application/hap+json'
|
27
|
+
|
28
|
+
def send_header(socket)
|
29
|
+
socket << STATUS_LINE + CRLF
|
30
|
+
socket << CONTENT_TYPE_LINE + CRLF
|
31
|
+
socket << content_length_line + CRLF
|
32
|
+
socket << CRLF
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_body(socket)
|
36
|
+
socket << body
|
37
|
+
end
|
38
|
+
|
39
|
+
def content_length_line
|
40
|
+
"Content-Length: #{body.length}"
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_reader :body, :socket
|
44
|
+
|
45
|
+
def encrypter
|
46
|
+
@_encrypter ||= RubyHome::HAP::HTTPEncryption.new(encryption_key, encrypter_params)
|
47
|
+
end
|
48
|
+
|
49
|
+
def encrypter_params
|
50
|
+
{
|
51
|
+
count: cache[:accessory_to_controller_count]
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def encryption_key
|
56
|
+
cache[:accessory_to_controller_key]
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache
|
60
|
+
RubyHome.socket_store[socket]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module RubyHome
|
2
|
-
module
|
2
|
+
module HAP
|
3
3
|
class HAPRequest < WEBrick::HTTPRequest
|
4
|
-
def initialize(
|
4
|
+
def initialize(config, sock)
|
5
|
+
@sock = sock
|
5
6
|
cache[:controller_to_accessory_count] ||= 0
|
6
7
|
|
7
|
-
super(
|
8
|
+
super(config)
|
8
9
|
end
|
9
10
|
|
10
|
-
def parse(socket
|
11
|
+
def parse(socket)
|
11
12
|
if decryption_time?
|
12
13
|
request_line = socket.read_nonblock(@buffer_size)
|
13
14
|
|
@@ -24,8 +25,14 @@ module RubyHome
|
|
24
25
|
cache[:controller_to_accessory_count] >= 1
|
25
26
|
end
|
26
27
|
|
28
|
+
def meta_vars
|
29
|
+
super.merge({"REQUEST_SOCKET" => sock})
|
30
|
+
end
|
31
|
+
|
27
32
|
private
|
28
33
|
|
34
|
+
attr_reader :sock
|
35
|
+
|
29
36
|
def decrypter
|
30
37
|
@_decrypter ||= RubyHome::HAP::HTTPDecryption.new(decryption_key, decrypter_params)
|
31
38
|
end
|
@@ -45,7 +52,7 @@ module RubyHome
|
|
45
52
|
end
|
46
53
|
|
47
54
|
def cache
|
48
|
-
|
55
|
+
RubyHome.socket_store[sock]
|
49
56
|
end
|
50
57
|
end
|
51
58
|
end
|