Packages
grizzly
0.6.5
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/command_class/association_group_info.ex
defmodule Grizzly.CommandClass.AssociationGroupInfo do
alias Grizzly.CommandClass.Mappings
require Logger
@type group_name_report :: %{group: non_neg_integer, name: String.t()}
@type groups_info_report :: %{groups_info: [group_info], dynamic: boolean}
@type group_info :: %{group: non_neg_integer, profile: group_profile}
@type group_profile :: atom
@type group_command_list_report :: %{group: non_neg_integer, commands: [group_command]}
@type group_command :: %{command_class: atom, command: atom}
@spec decode_group_name(non_neg_integer, binary) :: String.t()
def decode_group_name(length, binary) do
_ =
if byte_size(binary) != length do
_ =
Logger.warn(
"Mismatch between name length (#{inspect(length)} and name (#{inspect(binary)})"
)
end
binary
end
@spec decode_groups_info(non_neg_integer, binary) :: [group_info]
def decode_groups_info(group_count, encoded_groups_info) do
list = :erlang.binary_to_list(encoded_groups_info)
chunks = Enum.chunk_every(list, 7)
if Enum.count(chunks) != group_count do
_ = Logger.warn("Unexpected number of groups info. Expected #{group_count}.")
[]
else
Enum.reduce_while(
chunks,
[],
fn chunk, acc ->
binary = :erlang.list_to_binary(chunk)
case binary do
<<
group,
0x00,
profile_msb,
profile_lsb,
_reserved,
_event_code::size(16)
>> ->
{:cont, [%{group: group, profile: encode_profile(profile_msb, profile_lsb)} | acc]}
other ->
_ = Logger.warn("Invalid group info #{inspect(other)} ")
{:halt, []}
end
end
)
|> Enum.reverse()
end
end
@spec decode_group_command_list(non_neg_integer, binary) :: [group_command]
def decode_group_command_list(list_length, encoded_command_list) do
byte_list = :erlang.binary_to_list(encoded_command_list)
_ =
if Enum.count(byte_list) != list_length do
_ =
Logger.warn(
"Unexpected number of bytes in encoded command list. Expected #{list_length}, got #{
Enum.count(byte_list)
}"
)
end
{_, group_command_list} =
Enum.reduce(
byte_list,
{[], []},
fn byte, {buffer, acc} ->
updated_buffer = buffer ++ [byte]
case specified_command(updated_buffer) do
nil ->
{updated_buffer, acc}
{command_class, command} ->
{[], [%{command_class: command_class, command: command} | acc]}
end
end
)
group_command_list |> Enum.reverse()
end
defp encode_profile(0x00, 0x00), do: :general_na
defp encode_profile(0x00, 0x01), do: :general_lifeline
defp encode_profile(0x20, key), do: :"control_key_#{key}"
defp encode_profile(0x31, 0x01), do: :sensor_air_temperature
defp encode_profile(0x31, 0x05), do: :sensor_humidity
defp encode_profile(0x71, 0x01), do: :notification_smoke_alarm
defp encode_profile(0x71, 0x03), do: :notification_co2_alarm
defp encode_profile(0x71, _), do: :notification_unknown
defp encode_profile(0x32, 0x01), do: :meter_electric_kwh
defp encode_profile(0x32, 0x02), do: :meter_gas
defp encode_profile(0x32, 0x03), do: :meter_water
defp encode_profile(0x32, _), do: :meter_unknown
defp encode_profile(0x6B, key), do: :"irrigation_channel_#{key}"
defp encode_profile(_profile_msb, _profile_lsb), do: :unknown
defp specified_command([_]), do: nil
defp specified_command([cc_byte, _]) when cc_byte in [0xF1..0xFF], do: nil
defp specified_command([cc_byte1, cc_byte2, c_byte]) when cc_byte1 in [0xF1..0xFF] do
_ =
Logger.warn(
"Ignoring command #{c_byte} from extended command class #{cc_byte1}, #{cc_byte2}"
)
{:unknown, :unknown}
end
defp specified_command([cc_byte, c_byte]) do
command_class =
case Mappings.from_byte(cc_byte) do
{:unk, _} ->
_ = Logger.warn("Unmapped command class #{cc_byte}")
:"#{Integer.to_string(cc_byte, 16)}"
name ->
name
end
command =
case Mappings.command_from_byte(cc_byte, c_byte) do
{:unk, _} ->
_ = Logger.warn("Unmapped class #{c_byte} of command class #{inspect(command_class)}")
:"#{Integer.to_string(c_byte, 16)}"
name ->
name
end
{command_class, command}
end
defp specified_command(_), do: {:unknown, :unknown}
end