From de8f8aafdbcf2438f07632f254595bb71db44a8e Mon Sep 17 00:00:00 2001 From: Ben Youngblood Date: Thu, 8 Feb 2024 14:00:29 -0700 Subject: [PATCH] Implement Thermostat Fan Mode Supported Get/Report (#902) --- lib/grizzly/commands/table.ex | 3 + .../thermostat_fan_mode_supported_get.ex | 36 ++++++++++++ .../thermostat_fan_mode_supported_report.ex | 58 +++++++++++++++++++ lib/grizzly/zwave/decoder.ex | 2 + ...rmostat_fan_mode_supported_report_test.exs | 22 +++++++ 5 files changed, 121 insertions(+) create mode 100644 lib/grizzly/zwave/commands/thermostat_fan_mode_supported_get.ex create mode 100644 lib/grizzly/zwave/commands/thermostat_fan_mode_supported_report.ex create mode 100644 test/grizzly/zwave/commands/thermostat_fan_mode_supported_report_test.exs diff --git a/lib/grizzly/commands/table.ex b/lib/grizzly/commands/table.ex index 92f6ef57..994a64c4 100644 --- a/lib/grizzly/commands/table.ex +++ b/lib/grizzly/commands/table.ex @@ -276,6 +276,9 @@ defmodule Grizzly.Commands.Table do {:thermostat_fan_mode_get, {Commands.ThermostatFanModeGet, handler: {WaitReport, complete_report: :thermostat_fan_mode_report}}}, + {:thermostat_fan_mode_supported_get, + {Commands.ThermostatFanModeSupportedGet, + handler: {WaitReport, complete_report: :thermostat_fan_mode_supported_report}}}, # Thermostat fan state {:thermostat_fan_state_get, diff --git a/lib/grizzly/zwave/commands/thermostat_fan_mode_supported_get.ex b/lib/grizzly/zwave/commands/thermostat_fan_mode_supported_get.ex new file mode 100644 index 00000000..a127d8ca --- /dev/null +++ b/lib/grizzly/zwave/commands/thermostat_fan_mode_supported_get.ex @@ -0,0 +1,36 @@ +defmodule Grizzly.ZWave.Commands.ThermostatFanModeSupportedGet do + @moduledoc """ + This command is used to request the supported modes from the device. + """ + + @behaviour Grizzly.ZWave.Command + + alias Grizzly.ZWave.{Command, DecodeError} + alias Grizzly.ZWave.CommandClasses.ThermostatFanMode + + @impl Grizzly.ZWave.Command + @spec new(keyword()) :: {:ok, Command.t()} + def new(params) do + command = %Command{ + name: :thermostat_fan_mode_supported_get, + command_byte: 0x04, + command_class: ThermostatFanMode, + params: params, + impl: __MODULE__ + } + + {:ok, command} + end + + @impl Grizzly.ZWave.Command + @spec encode_params(Command.t()) :: binary() + def encode_params(_command) do + <<>> + end + + @impl Grizzly.ZWave.Command + @spec decode_params(binary()) :: {:ok, [keyword()]} | {:error, DecodeError.t()} + def decode_params(_binary) do + {:ok, []} + end +end diff --git a/lib/grizzly/zwave/commands/thermostat_fan_mode_supported_report.ex b/lib/grizzly/zwave/commands/thermostat_fan_mode_supported_report.ex new file mode 100644 index 00000000..1ade57bb --- /dev/null +++ b/lib/grizzly/zwave/commands/thermostat_fan_mode_supported_report.ex @@ -0,0 +1,58 @@ +defmodule Grizzly.ZWave.Commands.ThermostatFanModeSupportedReport do + @moduledoc """ + This command is used to report the device's supported thermostat modes. + + ## Parameters + + * `:modes` - the supported modes + """ + + @behaviour Grizzly.ZWave.Command + + import Grizzly.ZWave.Encoding + + alias Grizzly.ZWave.{Command, DecodeError} + alias Grizzly.ZWave.CommandClasses.ThermostatFanMode + + @type param :: {:modes, [ThermostatFanMode.mode()]} + + @impl Grizzly.ZWave.Command + @spec new([param()]) :: {:ok, Command.t()} + def new(params) do + command = %Command{ + name: :thermostat_fan_mode_supported_report, + command_byte: 0x05, + command_class: ThermostatFanMode, + params: params, + impl: __MODULE__ + } + + {:ok, command} + end + + @impl Grizzly.ZWave.Command + @spec encode_params(Command.t()) :: binary() + def encode_params(command) do + command + |> Command.param!(:modes) + |> Enum.map(&ThermostatFanMode.encode_mode/1) + |> encode_bitmask() + end + + @impl Grizzly.ZWave.Command + @spec decode_params(binary()) :: {:ok, [param()]} | {:error, DecodeError.t()} + def decode_params(binary) do + modes = + binary + |> decode_bitmask() + |> Enum.reduce([], fn mode, modes -> + case ThermostatFanMode.decode_mode(mode) do + {:ok, mode} -> [mode | modes] + {:error, _} -> modes + end + end) + |> Enum.reverse() + + {:ok, [modes: modes]} + end +end diff --git a/lib/grizzly/zwave/decoder.ex b/lib/grizzly/zwave/decoder.ex index f06c6306..02e6b660 100644 --- a/lib/grizzly/zwave/decoder.ex +++ b/lib/grizzly/zwave/decoder.ex @@ -331,6 +331,8 @@ defmodule Grizzly.ZWave.Decoder do {0x44, 0x01, Commands.ThermostatFanModeSet}, {0x44, 0x02, Commands.ThermostatFanModeGet}, {0x44, 0x03, Commands.ThermostatFanModeReport}, + {0x44, 0x04, Commands.ThermostatFanModeSupportedGet}, + {0x44, 0x05, Commands.ThermostatFanModeSupportedReport}, # Thermostat fan state {0x45, 0x02, Commands.ThermostatFanStateGet}, diff --git a/test/grizzly/zwave/commands/thermostat_fan_mode_supported_report_test.exs b/test/grizzly/zwave/commands/thermostat_fan_mode_supported_report_test.exs new file mode 100644 index 00000000..8378855e --- /dev/null +++ b/test/grizzly/zwave/commands/thermostat_fan_mode_supported_report_test.exs @@ -0,0 +1,22 @@ +defmodule Grizzly.ZWave.Commands.ThermostatFanModeSupportedReportTest do + use ExUnit.Case, async: true + + alias Grizzly.ZWave.Commands.ThermostatFanModeSupportedReport + + test "encodes params correctly" do + modes = [:auto_low, :low, :auto_high, :auto_medium] + + {:ok, cmd} = ThermostatFanModeSupportedReport.new(modes: modes) + + expected_binary = <<0b00010111>> + + assert expected_binary == ThermostatFanModeSupportedReport.encode_params(cmd) + end + + test "decodes params correctly" do + binary = <<0b00010111>> + + assert {:ok, [modes: [:auto_low, :low, :auto_high, :auto_medium]]} == + ThermostatFanModeSupportedReport.decode_params(binary) + end +end