Packages
grizzly
8.11.3
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/command_classes/sensor_multilevel.ex
defmodule Grizzly.ZWave.CommandClasses.SensorMultilevel do
@moduledoc """
"SensorMultilevel" Command Class
The Multilevel Sensor Command Class is used to advertise numerical sensor readings.
"""
@behaviour Grizzly.ZWave.CommandClass
alias Grizzly.ZWave.Encoding
@impl Grizzly.ZWave.CommandClass
def byte(), do: 0x31
@impl Grizzly.ZWave.CommandClass
def name(), do: :sensor_multilevel
@sensor_types [
# id, name, scales (in order by byte value)
{0x01, :temperature, [:c, :f]},
{0x02, :general, [:percentage, :dimensionless]},
{0x03, :luminance, [:percentage, :lux]},
{0x04, :power, [:watts, :btus_per_hour]},
{0x05, :humidity, [:percentage, :absolute]},
{0x06, :velocity, [:meters_per_second, :miles_per_hour]},
{0x07, :direction, [:degrees]},
{0x08, :atmospheric_pressure, [:kilopascals, :inches_of_mercury]},
{0x09, :barometric_pressure, [:kilopascals, :inches_of_mercury]},
{0x0A, :solar_radiation, [:watts_per_square_meter]},
{0x0B, :dew_point, [:c, :f]},
{0x0C, :rain_rate, [:millimeters_per_hour, :inches_per_hour]},
{0x0D, :tide_level, [:meters, :feet]},
{0x0E, :weight, [:kilograms, :pounds]},
{0x0F, :voltage, [:volts, :millivolts]},
{0x10, :current, [:amps, :milliamps]},
{0x11, :co2_level, [:parts_per_million]},
{0x12, :air_flow, [:cubic_meters_per_hour, :cubic_feet_per_minute]},
{0x13, :tank_capacity, [:liters, :cubic_meters, :gallons]},
{0x14, :distance, [:meters, :centimeters, :feet]},
{0x15, :angle_position, [:percentage, :degrees]},
{0x16, :rotation, [:revolutions_per_minute, :hertz]},
{0x17, :water_temperature, [:c, :f]},
{0x18, :soil_temperature, [:c, :f]},
{0x19, :seismic_intensity, [:mercalli, :european_macroseismic, :liedu, :shindo]},
{0x1A, :seismic_magnitude, [:local, :moment, :surface_wave, :body_wave]},
{0x1B, :ultraviolet, [:uv_index]},
{0x1C, :electrical_resistivity, [:ohm_meters]},
{0x1D, :electrical_conductivity, [:siemens_per_meter]},
{0x1E, :loudness, [:decibels, :a_weighted_decibels]},
{0x1F, :moisture, [:percentage, :cubic_meters_per_cubic_meter, :kiloohms, :water_activity]},
{0x20, :frequency, [:hertz, :kilohertz]},
{0x21, :time, [:seconds]},
{0x22, :target_temperature, [:c, :f]},
{0x23, :particulate_matter_2_5, [:moles_per_cubic_meter, :micrograms_per_cubic_meter]},
{0x24, :formaldehyde_level, [:moles_per_cubic_meter]},
{0x25, :radon_concentration, [:becquerels_per_cubic_meter, :picocuries_per_liter]},
{0x26, :methane_density, [:moles_per_cubic_meter]},
{0x27, :voc_level, [:moles_per_cubic_meter, :parts_per_million]},
{0x28, :co_level, [:moles_per_cubic_meter, :parts_per_million]},
{0x29, :soil_humidity, [:percentage]},
{0x2A, :soil_reactivity, [:ph]},
{0x2B, :soil_salinity, [:moles_per_cubic_meter]},
{0x2C, :heart_rate, [:beats_per_minute]},
{0x2D, :blood_pressure, [:mm_hg_systolic, :mm_hg_diastolic]},
{0x2E, :muscle_mass, [:kilograms]},
{0x2F, :fat_mass, [:kilograms]},
{0x30, :bone_mass, [:kilograms]},
{0x31, :total_body_water, [:kilograms]},
{0x32, :base_metabolic_rate, [:joules]},
{0x33, :body_mass_index, [:index]},
{0x34, :acceleration_x_axis, [:meters_per_square_second]},
{0x35, :acceleration_y_axis, [:meters_per_square_second]},
{0x36, :acceleration_z_axis, [:meters_per_square_second]},
{0x37, :smoke_density, [:percentage]},
{0x38, :water_flow, [:liters_per_hour]},
{0x39, :water_pressure, [:kilopascals]},
{0x3A, :rf_signal_strength, [:percentage, :decibel_milliwatts]},
{0x3B, :particulate_matter_10, [:moles_per_cubic_meter, :micrograms_per_cubic_meter]},
{0x3C, :respiratory_rate, [:breaths_per_minute]},
{0x3D, :relative_modulation_level, [:percentage]},
{0x3E, :boiler_water_temperature, [:c, :f]},
{0x3F, :domestic_hot_water_temperature, [:c, :f]},
{0x40, :outside_temperature, [:c, :f]},
{0x41, :exhaust_temperature, [:c, :f]},
{0x42, :water_chlorine_level, [:milligrams_per_liter]},
{0x43, :water_acidity, [:ph]},
{0x44, :water_oxidation_reduction_potential, [:millivolts]},
{0x45, :heart_rate_lf_to_hf_ratio, [:unitless]},
{0x46, :motion_direction, [:degrees]},
{0x47, :applied_force, [:newtons]},
{0x48, :return_air_temperature, [:c, :f]},
{0x49, :supply_air_temperature, [:c, :f]},
{0x4A, :condenser_coil_temperature, [:c, :f]},
{0x4B, :evaporator_coil_temperature, [:c, :f]},
{0x4C, :liquid_line_temperature, [:c, :f]},
{0x4D, :discharge_line_temperature, [:c, :f]},
{0x4E, :suction_pressure, [:kilopascals, :pounds_per_square_inch]},
{0x4F, :discharge_pressure, [:kilopascals, :pounds_per_square_inch]},
{0x50, :defrost_temperature, [:c, :f]},
{0x51, :ozone, [:micrograms_per_cubic_meter]},
{0x52, :sulfur_dioxide, [:micrograms_per_cubic_meter]},
{0x53, :nitrogen_dioxide, [:micrograms_per_cubic_meter]},
{0x54, :ammonia, [:micrograms_per_cubic_meter]},
{0x55, :lead, [:micrograms_per_cubic_meter]},
{0x56, :particulate_matter_1, [:micrograms_per_cubic_meter]},
{0x57, :person_counter_entering, [:unitless]},
{0x58, :person_counter_exiting, [:unitless]}
]
@sensor_types_by_id Map.new(@sensor_types, &{elem(&1, 0), elem(&1, 1)})
@sensor_types_by_name Map.new(@sensor_types, &{elem(&1, 1), elem(&1, 0)})
@sensor_scales_by_type Map.new(@sensor_types, &{elem(&1, 1), elem(&1, 2)})
@spec all_sensor_types() :: [atom()]
def all_sensor_types(), do: Enum.map(@sensor_types, &elem(&1, 1))
@spec sensor_type_scales(atom()) :: [atom()]
def sensor_type_scales(sensor_type), do: Map.get(@sensor_scales_by_type, sensor_type)
@spec encode_sensor_type(atom() | byte()) :: byte()
def encode_sensor_type(sensor_type) when sensor_type in 0..255, do: sensor_type
def encode_sensor_type(sensor_type) do
Map.fetch!(@sensor_types_by_name, sensor_type)
end
@spec decode_sensor_type(byte()) :: {:ok, atom()} | :error
def decode_sensor_type(byte) do
Map.fetch(@sensor_types_by_id, byte)
end
@spec decode_sensor_types(binary) :: [atom()]
def decode_sensor_types(binary) do
binary
|> Encoding.decode_bitmask()
|> Enum.reduce([], fn v, acc ->
case decode_sensor_type(v + 1) do
{:ok, sensor_type} -> [sensor_type | acc]
:error -> acc
end
end)
|> Enum.reverse()
end
@spec encode_sensor_types([atom]) :: binary
def encode_sensor_types(sensor_types) do
sensor_types
|> Enum.map(&(encode_sensor_type(&1) - 1))
|> Encoding.encode_bitmask()
end
@spec encode_sensor_scale(atom(), atom() | byte()) :: byte() | nil
def encode_sensor_scale(_, scale) when scale in 0..255, do: scale
def encode_sensor_scale(sensor_type, scale) do
byte =
@sensor_scales_by_type
|> Map.get(sensor_type, [])
|> Enum.find_index(&(&1 == scale))
if(byte in 0..255, do: byte, else: 0)
end
@spec decode_sensor_scale(atom(), byte()) :: atom()
def decode_sensor_scale(sensor_type, index) do
@sensor_scales_by_type
|> Map.get(sensor_type, [])
|> Enum.at(index, :unknown)
end
@spec encode_sensor_scales(atom(), [atom()]) :: <<_::8>>
def encode_sensor_scales(sensor_type, scales) do
scales
|> Enum.map(&encode_sensor_scale(sensor_type, &1))
|> Encoding.encode_bitmask()
end
@spec decode_sensor_scales(atom(), binary()) :: [atom()]
def decode_sensor_scales(sensor_type, scales) do
scales
|> Encoding.decode_bitmask()
|> Enum.map(&decode_sensor_scale(sensor_type, &1))
end
end