Packages
grizzly
7.0.4
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/mix/tasks/zwave.gen.xml_mappings.ex
if Code.ensure_loaded?(SweetXml) do
defmodule Mix.Tasks.Zwave.Gen.XmlMappings do
@moduledoc """
Generates a module that provides mappings based on the data in `ZWave_custom_cmd_classes.xml`.
mix zwave.gen.xml_mappings
### Flags
* `--input <path>` - reads the xml from the provided path
* `--dry-run` - print the generated module out to the console
* `--output <path>` - writes the generated module at the provided path
"""
use Mix.Task
import SweetXml
@shortdoc "Generates a module that provides mappings based on the data in `ZWave_custom_cmd_classes.xml`"
@switches [dry_run: :boolean]
@skip_command_classes [:zwave_cmd_class, :zwave_cmd_class_lr]
@command_class_name_overrides %{
0x4F => :zip_6lowpan,
0x59 => :association_group_info,
0x96 => :av_content_renderer_status
}
def run(args) do
{opts, _, _} = OptionParser.parse(args, switches: @switches)
input_path = Keyword.get(opts, :input, "resources/ZWave_custom_cmd_classes.xml")
doc = input_path |> File.read!() |> parse()
command_class_mappings = build_macro(:command_class_mappings, command_class_mappings(doc))
basic_device_class_mappings =
build_macro(:basic_device_class_mappings, basic_device_class_mappings(doc))
generic_device_class_mappings =
build_macro(:generic_device_class_mappings, generic_device_class_mappings(doc))
specific_device_class_mappings =
build_macro(:specific_device_class_mappings, specific_device_class_mappings(doc))
module =
quote do
defmodule Grizzly.ZWave.GeneratedMappings do
@moduledoc false
unquote(command_class_mappings)
unquote(basic_device_class_mappings)
unquote(generic_device_class_mappings)
unquote(specific_device_class_mappings)
end
end
module_code = module |> Macro.to_string() |> Code.format_string!()
module_code =
"""
# !! THIS FILE IS GENERATED BY `mix zwave.gen.xml`
# !! DO NOT EDIT DIRECTLY
#{module_code}
"""
if opts[:dry_run] do
Mix.shell().info(module_code)
else
output_path = Keyword.get(opts, :output, "lib/grizzly/zwave/generated_mappings.ex")
Mix.Generator.create_file(output_path, module_code)
end
end
defp build_macro(name, value) do
quote do
def unquote(name)(), do: unquote(value)
end
end
defp command_class_mappings(doc) do
doc
|> xpath(~x"//zw_classes/cmd_class"l, key: ~x"@key"s, name: ~x"@name"s)
|> Enum.map(key_name_mapper("COMMAND_CLASS_", @command_class_name_overrides))
|> Enum.uniq_by(fn {key, _} -> key end)
|> Enum.reject(&(elem(&1, 1) in @skip_command_classes))
|> Enum.sort()
end
defp basic_device_class_mappings(doc) do
doc
|> xpath(~x"//zw_classes/bas_dev"l, key: ~x"@key"s, name: ~x"@name"s)
|> Enum.map(key_name_mapper("BASIC_TYPE_"))
|> Enum.sort()
end
defp generic_device_class_mappings(doc) do
doc
|> xpath(~x"//zw_classes/gen_dev"l, key: ~x"@key"s, name: ~x"@name"s)
|> Enum.map(key_name_mapper("GENERIC_TYPE_"))
|> Enum.sort()
end
defp specific_device_class_mappings(doc) do
doc
|> xpath(~x"//zw_classes/gen_dev"l,
generic_type: ~x"@name"s,
specific_types: [~x"./spec_dev"l, key: ~x"@key"s, name: ~x"@name"s]
)
|> Enum.flat_map(fn %{generic_type: generic_type, specific_types: specific_types} ->
Enum.map(specific_types, fn %{name: name, key: key} ->
generic_type = parse_name(generic_type, "GENERIC_TYPE_")
specific_type = parse_name(name, "SPECIFIC_TYPE_")
key = parse_hex_string(key)
Macro.escape({generic_type, key, specific_type})
end)
end)
|> Enum.sort()
end
defp key_name_mapper(name_prefix, name_overrides \\ %{}) do
fn %{name: name, key: key} ->
key = parse_hex_string(key)
name = Map.get(name_overrides, key, parse_name(name, name_prefix))
{key, name}
end
end
defp parse_hex_string(string) do
string |> String.replace_leading("0x", "") |> String.to_integer(16)
end
defp parse_name(name, prefix) do
name |> String.replace(prefix, "") |> Macro.underscore() |> String.to_atom()
end
end
end