Packages
grizzly
6.0.0
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/zwave_firmware.ex
defmodule Grizzly.ZwaveFirmware do
@moduledoc false
alias Grizzly.FirmwareError
require Logger
@type firmware_info :: %{chip_type: non_neg_integer(), version: String.t(), path: Path.t()}
@doc """
Update the firmware on the Z-Wave module if an update is available
"""
@spec maybe_run_zwave_firmware_update(Grizzly.Options.t()) :: :ok
def maybe_run_zwave_firmware_update(options) do
firmware_update_requested? = options.update_zwave_firmware
if firmware_update_requested?, do: attempt_firmware_update(options)
:ok
end
defp attempt_firmware_update(options) do
zwave_module_info = zwave_module_info(options)
fw_image_file = find_fw_image_file(options, zwave_module_info)
upload_zwave_firmware_update(fw_image_file, options)
report(options, :success)
rescue
e in FirmwareError ->
error = %FirmwareError{e | stack_trace: Exception.format(:error, e, __STACKTRACE__)}
report(options, {:error, error})
# Firmware update not possible due to code error. Skip it.
e in RuntimeError ->
error = %FirmwareError{
message: "Runtime error: #{e.message}",
stack_trace: Exception.format(:error, e, __STACKTRACE__),
fatal?: false
}
report(options, {:error, error})
end
# Looks for a valid upgrade fw image file
defp find_fw_image_file(options, zwave_module_info) do
firmware_info_list = options.zwave_firmware
case find_upgrade_info(firmware_info_list, zwave_module_info) do
%{path: path} ->
path
_ ->
raise FirmwareError,
message:
"No firmware upgrade path found in #{inspect(firmware_info_list)} for current firmware #{inspect(zwave_module_info)}",
fatal?: false
end
end
defp find_upgrade_info(
firmware_info_list,
%{chip_type: chip_type, version: current_version} = _current_firmware
) do
Enum.find(firmware_info_list, fn %{
chip_type: target_chip_type,
version: target_version_s
} ->
target_version = Version.parse!(target_version_s)
target_chip_type == chip_type and
upgrade_valid?(current_version, target_version)
end)
end
# {:ok, %{chip_type: 7, version: "7.15.2"}}
defp zwave_module_info(options) do
{answer, 0} = System.cmd(options.zw_programmer_path, ["-s", options.serial_port, "-t"])
if String.contains?(answer, "Serial Init failed") do
raise FirmwareError, message: "zw_programmer said serial init failed", fatal?: true
else
extract_zwave_module_info(answer)
end
end
# "Using serial device /dev/ttyS4\nConnected to Serial device: OK\nSerial version: 9, Chip type: 7, Chip version: 0, SDK: 7.15.02, ..."
# {:ok, %{chip_type: chip_type, version: current_version}}
defp extract_zwave_module_info(answer) do
Logger.info("[Grizzly] Extracting current version from #{inspect(answer)}")
regex = ~r/Chip type: (?<chip_type>\d+).*SDK:\s*(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)/m
%{"chip_type" => chip_type_s, "major" => major_s, "minor" => minor_s, "patch" => patch_s} =
Regex.named_captures(regex, answer)
{chip_type, ""} = Integer.parse(chip_type_s)
{major, ""} = Integer.parse(major_s)
{minor, ""} = Integer.parse(minor_s)
{patch, ""} = Integer.parse(patch_s)
%{chip_type: chip_type, version: %{major: major, minor: minor, patch: patch}}
end
defp upgrade_valid?(current_version, target_version) do
cond do
target_version.major > current_version.major ->
true
target_version.major == current_version.major and
target_version.minor > current_version.minor ->
true
target_version.major == current_version.major and
target_version.minor == current_version.minor and
target_version.patch > current_version.patch ->
true
true ->
false
end
end
defp upload_zwave_firmware_update(firmware_path, options) do
:ok = report(options, :started)
Logger.info(
"[Grizzly] Uploading ZWave controller firmware image #{firmware_path} via #{options.serial_port}}"
)
{result, code} =
System.cmd(options.zw_programmer_path, ["-s", options.serial_port, "-p", firmware_path])
if code == 0 do
Logger.info("[Grizzly] Hub firmware upgrade successful")
:ok
else
raise FirmwareError, message: "zw_programmer exited with #{code}: #{result}", fatal?: true
end
end
defp report(options, status) do
# Report the firmware update status
options.status_reporter.zwave_firmware_update_status(status)
end
end