Skip to content

Commit

Permalink
Expose maximum/minimum/step values of a numeric characteristics (#126)
Browse files Browse the repository at this point in the history
This exposes the optional Properties of Characteristic Objects in JSON 

- Minimum Value
- Maximum Value
- Step Value

These characteristics are only relevant for characteristics of format
int or float. They allow finer specification of characteristics beyond
the defaults. For example: if someone wants to limit the cooling
temperature of an AC unit `heater_cooler` with no heater between 17C and
31C in 1C steps.
  • Loading branch information
karlentwistle authored Jul 22, 2023
1 parent f50b9ae commit c6e035c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
24 changes: 24 additions & 0 deletions lib/ruby_home/characteristic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,30 @@ def valid_values
constraints.fetch("ValidValues", {}).keys.map(&:to_i)
end

def minimum_value
return unless numeric_format?

constraints["MinimumValue"]
end

def maximum_value
return unless numeric_format?

constraints["MaximumValue"]
end

def step_value
return unless numeric_format?

constraints["StepValue"]
end

NUMERIC_FORMATS = ["float", "uint8", "int32", "uint32"].freeze

def numeric_format?
NUMERIC_FORMATS.include?(format)
end

def method_missing(method_name, *args, &block)
value.send(method_name, *args, &block)
end
Expand Down
11 changes: 11 additions & 0 deletions lib/ruby_home/http/serializers/characteristic_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def record_hash(characteristic)
}
.merge(value_hash(characteristic))
.merge(valid_values_hash(characteristic))
.merge(numeric_constraints(characteristic))
end

private
Expand All @@ -42,6 +43,16 @@ def valid_values_hash(characteristic)
{"valid-values" => characteristic.valid_values}
end
end

def numeric_constraints(characteristic)
return {} unless characteristic.numeric_format?

{
"minValue" => characteristic.minimum_value,
"maxValue" => characteristic.maximum_value,
"minStep" => characteristic.step_value
}.compact
end
end
end
end
30 changes: 30 additions & 0 deletions spec/http/requests/accessories_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,36 @@
valid_values = JSON.parse(last_response.body)["accessories"][0]["services"][0]["characteristics"][0]["valid-values"]
expect(valid_values).to eql([0, 1])
end

it "includes float format characteristics numeric properties" do
heater_cooler = RubyHome::ServiceFactory.create(:heater_cooler, cooling_threshold_temperature: 10)
cooling_threshold_temperature = heater_cooler.cooling_threshold_temperature

get "/accessories", nil, {"CONTENT_TYPE" => "application/hap+json"}

characteristics = JSON.parse(last_response.body).dig("accessories", 0, "services", 0, "characteristics")
characteristic = characteristics.find { |c| c["iid"] == cooling_threshold_temperature.instance_id }
expect(characteristic).to include(
"minValue" => 10,
"maxValue" => 35,
"minStep" => 0.1
)
end

it "includes int format characteristics numeric properties" do
window_covering = RubyHome::ServiceFactory.create(:window_covering, target_horizontal_tilt_angle: 0)
target_horizontal_tilt_angle = window_covering.target_horizontal_tilt_angle

get "/accessories", nil, {"CONTENT_TYPE" => "application/hap+json"}

characteristics = JSON.parse(last_response.body).dig("accessories", 0, "services", 0, "characteristics")
characteristic = characteristics.find { |c| c["iid"] == target_horizontal_tilt_angle.instance_id }
expect(characteristic).to include(
"minValue" => -90,
"maxValue" => 90,
"minStep" => 1
)
end
end

def create_fan_accessory
Expand Down

0 comments on commit c6e035c

Please sign in to comment.