Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add planckian helpers for HSBType #353

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion lib/openhab/core/types/hsb_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,80 @@ def to_s
# @return [[PercentType, PercentType, PercentType]]

# @!attribute [r] cct
# @return [QuantityType] The color temperature in Kelvin
# @return [QuantityType] The correlated color temperature in Kelvin
# @since openHAB 4.3
# @see https://en.wikipedia.org/wiki/Planckian_locus Planckian Locus
def cct
ColorUtil.xy_to_kelvin(to_xy[0..1].map { |x| x.double_value / 100 }) | "K"
end

# @!attribute [r] duv
# The distance that this color is from the planckian locus
#
# @return [Float] The delta u, v
#
# @see planckian?
# @see planckian_cct
# @see https://en.wikipedia.org/wiki/Planckian_locus Planckian Locus
# @since openHAB 4.3
def duv
ColorUtil.xy_to_duv(to_xy[0..1].map { |x| x.double_value / 100 })
end

# Checks if this color is within a certain tolerance of the planckian locus ("white")
#
# @param [Float] duv_tolerance The maximum allowed distance from the planckian locus
# @param [Numeric, PercentType] maximum_saturation The maximum allowed saturation.
# Some colors (bright green for example) may be close to the planckian locus,
# but you don't want to treat them as "white" because they are very saturated.
# @return [true, false]
#
# @note The parameters and defaults for this method are subject to change in future
# releases of this library, and should be considered beta. For now, the default
# parameters should be sufficient to detect most colors that Apple's HomeKit color
# temperature color chooser uses as planckian, without detecting most other "real"
# colors as planckian.
# @see duv
# @see planckian_cct
# @see https://en.wikipedia.org/wiki/Planckian_locus Planckian Locus
# @since openHAB 4.3
def planckian?(duv_tolerance: 0.015, maximum_saturation: 75)
duv.abs < duv_tolerance && saturation < maximum_saturation
end
alias_method :white_cct?, :planckian?

# Returns the color temperature of this color _if_ it is within a certain tolerance
# of the planckian locus ("white"), otherwise returns `nil`.
#
# @param [Range, NumberItem] range An allowed range to additionally restrict
# if the CCT should be returned. A NumberItem that represents a CCT channel
# may be provided, and {NumberItem#range NumberItem#range} will be used instead. If the range
# does not have units (is {QuantityType}), it is interpreted as being in Kelvin.
# @return [QuantityType, nil] The color temperature in Kelvin
# (unless the range is in mireds; then it will be in mireds)
#
# @note Additional parameters are forwarded to {#planckian?}
# @see planckian?
# @see https://en.wikipedia.org/wiki/Planckian_locus Planckian Locus
# @since openHAB 4.3
def planckian_cct(range: nil, **kwargs)
return unless planckian?(**kwargs)

range = range.range if range.is_a?(NumberItem)
cct = self.cct
if range
range_type = range.begin || range.end
if !range_type.is_a?(QuantityType)
range = Range.new(range.begin | "K", range.end | "K")
elsif range_type.unit.to_s == "mired"
cct |= "mired"
end
end
return nil if range && !range.cover?(cct)

cct
end
alias_method :white_cct, :planckian_cct
end
end
end
Expand Down
41 changes: 41 additions & 0 deletions spec/openhab/core/types/hsb_type_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,47 @@
end
end

describe "#planckian_cct", if: OpenHAB::Core.version >= OpenHAB::Core::V4_3 do
it "returns a value for a pure 'white'" do
warm_white = HSBType.from_cct(2700)
expect(warm_white.planckian_cct.to_i).to be 2699
end

it "returns a value if in range (bare range)" do
warm_white = HSBType.from_cct(2700)
expect(warm_white.planckian_cct(range: 2000..6000).to_i).to be 2699
end

it "returns a value if in range (K range)" do
warm_white = HSBType.from_cct(2700)
expect(warm_white.planckian_cct(range: (2000 | "K")..(6000 | "K")).to_i).to be 2699
end

it "returns a value if in range (mired range)" do
warm_white = HSBType.from_cct(2700)
expect(warm_white.planckian_cct(range: (167 | "mired")..(500 | "mired")).to_i).to be 370
end

it "returns nil for red" do
expect(HSBType::RED.planckian_cct).to be_nil
end

it "returns nil if the CCT is out of range (bare range)" do
color = HSBType.from_cct(2000)
expect(color.planckian_cct(range: 2700..6000)).to be_nil
end

it "returns nil if the CCT is out of range (K range)" do
color = HSBType.from_cct(2000)
expect(color.planckian_cct(range: (2700 | "K")..(6000 | "K"))).to be_nil
end

it "returns nil if the CCT is out of range (mired range)" do
color = HSBType.from_cct(2000)
expect(color.planckian_cct(range: (167 | "mired")..(370 | "mired"))).to be_nil
end
end

it "is inspectable" do
expect(HSBType.new.inspect).to eql "0 °,0%,0%"
end
Expand Down