Skip to content

Commit

Permalink
Implement Thermostat Setpoint Capabilities Get/Report (#901)
Browse files Browse the repository at this point in the history
Required for Thermostat Setpoint v3
  • Loading branch information
bjyoungblood authored Feb 8, 2024
1 parent 6334e26 commit 8be12e3
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/grizzly/commands/table.ex
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ defmodule Grizzly.Commands.Table do
{:thermostat_setpoint_supported_get,
{Commands.ThermostatSetpointSupportedGet,
handler: {WaitReport, complete_report: :thermostat_setpoint_supported_report}}},
{:thermostat_setpoint_capabilities_get,
{Commands.ThermostatSetpointCapabilitiesGet,
handler: {WaitReport, complete_report: :thermostat_setpoint_capabilities_report}}},

# Thermostat fan mode
{:thermostat_fan_mode_set, {Commands.ThermostatFanModeSet, handler: AckResponse}},
Expand Down
43 changes: 43 additions & 0 deletions lib/grizzly/zwave/commands/thermostat_setpoint_capabilities_get.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule Grizzly.ZWave.Commands.ThermostatSetpointCapabilitiesGet do
@moduledoc """
This command is used request the supported setpoint value range for a setpoint type.
## Parameters
* `:type` - The setpoint type to query capabilities for.
"""

@behaviour Grizzly.ZWave.Command

alias Grizzly.ZWave.{Command, DecodeError}
alias Grizzly.ZWave.CommandClasses.ThermostatSetpoint

@type param() :: {:type, ThermostatSetpoint.type()}

@impl Grizzly.ZWave.Command
@spec new([param()]) :: {:ok, Command.t()}
def new(params) do
command = %Command{
name: :thermostat_setpoint_capabilities_get,
command_byte: 0x09,
command_class: ThermostatSetpoint,
params: params,
impl: __MODULE__
}

{:ok, command}
end

@impl Grizzly.ZWave.Command
@spec encode_params(Command.t()) :: binary()
def encode_params(command) do
type = Command.param!(command, :type)
<<0::4, ThermostatSetpoint.encode_type(type)::4>>
end

@impl Grizzly.ZWave.Command
@spec decode_params(binary()) :: {:ok, [param()]} | {:error, DecodeError.t()}
def decode_params(<<_reserved::4, type::4>>) do
{:ok, [type: ThermostatSetpoint.decode_type(type)]}
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
defmodule Grizzly.ZWave.Commands.ThermostatSetpointCapabilitiesReport do
@moduledoc """
This command is used advertise the supported setpoint value range for a given setpoint type.
## Parameters
* `:type` - the setpoint type
* `:min_scale` - scale of the minimum value
* `:min_value` - minimum value
* `:max_scale` - scale of the maximum value
* `:max_value` - maximum value
"""

@behaviour Grizzly.ZWave.Command

import Grizzly.ZWave.CommandClasses.ThermostatSetpoint
import Grizzly.ZWave.Encoding

alias Grizzly.ZWave.{Command, DecodeError}
alias Grizzly.ZWave.CommandClasses.ThermostatSetpoint

@type param ::
{:type, ThermostatSetpoint.type()}
| {:min_scale, ThermostatSetpoint.scale()}
| {:min_value, number()}
| {:max_scale, ThermostatSetpoint.scale()}
| {:max_value, number()}

@impl Grizzly.ZWave.Command
@spec new([param()]) :: {:ok, Command.t()}
def new(params) do
command = %Command{
name: :thermostat_setpoint_capabilities_report,
command_byte: 0x0A,
command_class: ThermostatSetpoint,
params: params,
impl: __MODULE__
}

{:ok, command}
end

@impl Grizzly.ZWave.Command
@spec encode_params(Command.t()) :: binary()
def encode_params(command) do
type = Command.param!(command, :type)
min_scale = Command.param!(command, :min_scale)
min_value = Command.param!(command, :min_value)
max_scale = Command.param!(command, :max_scale)
max_value = Command.param!(command, :max_value)

{min_int_value, min_precision, min_byte_size} = encode_zwave_float(min_value)
{max_int_value, max_precision, max_byte_size} = encode_zwave_float(max_value)

<<0::4, encode_type(type)::4, min_precision::3, encode_scale(min_scale)::2, min_byte_size::3,
min_int_value::size(min_byte_size)-unit(8), max_precision::3, encode_scale(max_scale)::2,
max_byte_size::3, max_int_value::size(max_byte_size)-unit(8)>>
end

@impl Grizzly.ZWave.Command
@spec decode_params(binary()) :: {:ok, [param()]} | {:error, DecodeError.t()}
def decode_params(
<<_::4, type::4, min_precision::3, min_scale::2, min_byte_size::3,
min_int_value::size(min_byte_size)-unit(8), max_precision::3, max_scale::2,
max_byte_size::3, max_int_value::size(max_byte_size)-unit(8)>>
) do
with {:ok, min_scale} <- decode_scale(min_scale),
{:ok, max_scale} <- decode_scale(max_scale) do
{:ok,
[
type: decode_type(type),
min_scale: min_scale,
min_value: decode_zwave_float(min_int_value, min_precision),
max_scale: max_scale,
max_value: decode_zwave_float(max_int_value, max_precision)
]}
else
{:error, %DecodeError{} = err} ->
{:error, %{err | command: :thermostat_setpoint_capabilities_report}}
end
end
end
2 changes: 2 additions & 0 deletions lib/grizzly/zwave/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ defmodule Grizzly.ZWave.Decoder do
{0x43, 0x03, Commands.ThermostatSetpointReport},
{0x43, 0x04, Commands.ThermostatSetpointSupportedGet},
{0x43, 0x05, Commands.ThermostatSetpointSupportedReport},
{0x43, 0x09, Commands.ThermostatSetpointCapabilitiesGet},
{0x43, 0x0A, Commands.ThermostatSetpointCapabilitiesReport},

# Thermostat fan mode
{0x44, 0x01, Commands.ThermostatFanModeSet},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule Grizzly.ZWave.Commands.ThermostatSetpointCapabilitiesGetTest do
use ExUnit.Case, async: true

alias Grizzly.ZWave.Commands.ThermostatSetpointCapabilitiesGet

test "encodes params correctly" do
params = [
type: :heating
]

{:ok, cmd} = ThermostatSetpointCapabilitiesGet.new(params)

expected_binary = <<0::4, 1::4>>
assert expected_binary == ThermostatSetpointCapabilitiesGet.encode_params(cmd)
end

test "decodes params correctly" do
binary = <<0::4, 1::4>>

{:ok, [type: :heating]} = ThermostatSetpointCapabilitiesGet.decode_params(binary)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Grizzly.ZWave.Commands.ThermostatSetpointCapabilitiesReportTest do
use ExUnit.Case, async: true

alias Grizzly.ZWave.Commands.ThermostatSetpointCapabilitiesReport

test "encodes params correctly" do
params = [
type: :heating,
min_scale: :c,
min_value: 10.5,
max_scale: :c,
max_value: 30
]

{:ok, cmd} = ThermostatSetpointCapabilitiesReport.new(params)

expected_binary = <<0::4, 1::4, 1::3, 0::2, 1::3, 105, 0::3, 0::2, 1::3, 30>>
assert expected_binary == ThermostatSetpointCapabilitiesReport.encode_params(cmd)
end

test "decodes params correctly" do
binary = <<0::4, 1::4, 1::3, 0::2, 1::3, 105, 0::3, 0::2, 1::3, 30>>

{:ok, [type: :heating, min_scale: :c, min_value: 10.5, max_scale: :c, max_value: 30]} =
ThermostatSetpointCapabilitiesReport.decode_params(binary)
end
end

0 comments on commit 8be12e3

Please sign in to comment.