smartrent / grizzly

Elixir Z-Wave Library

Home Page:https://hex.pm/packages/grizzly

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Interpret signal strength in Grizzly

fhunleth opened this issue · comments

The signal strength reports are currently 5-tuples in the transmission_stat type. Each item in the tuple is the strength for one hop on the path to the node. Z-Wave has a hardcoded max of 5 hops and if you only have one hop to get to a device, then the last 4 tuples are :not_available.

There's getting to be some code that interprets Z-Wave signal strength in other places that may or may not be doing the right thing. It seems like the knowledge for how to interpret signal strength would best be kept here.

I'd like to propose changing the 5-tuple to a map with the following fields:

  • :rssi_4bars - 0..4 | :unknown where :unknown means that there's no measurement, 0 is no signal, and 4 is a really good signal. This is to avoid copy/pasting RSSI->icon conversion formulas around.
  • :rssi_dbm - an aggregate RSSI measurement for places that just want one RSSI measurement. For example, the RSSI of the weakest hop. If unknown, then :unknown
  • :rssi_hops - a list of RSSI measurements. The first item is the RSSI to the first hop, and so on. This is similar to the 5-tuple, but using a list. I hope that it's possible to make the list the number of hops and not just always have a length 5 list. The motivation here is that the current code processing the 5-tuple just converts the tuple to a list, so it seems like it might as well be a list to begin with.

What do you think?

The transmission_stats would go from

@type transmission_stat() ::
          {:transmit_channel, non_neg_integer()}
          | {:ack_channel, non_neg_integer()}
          | {:rssi, {rssi_value(), rssi_value(), rssi_value(), rssi_value(), rssi_value()}}
          | {:last_working_route,
             {ZWave.node_id(), ZWave.node_id(), ZWave.node_id(), ZWave.node_id()},
             {transmit_speed(), :kbit_sec}}
          | {:transmission_time, non_neg_integer()}
          | {:route_changed, :not_changed | :changed}

to

@type transmission_stat() ::
          {:transmit_channel, non_neg_integer()}
          | {:ack_channel, non_neg_integer()}
          | {:rssi_hops, [rssi_value()]}
          | {:rssi_4bars, 0..4 | :unknown}
          | {:rssi_dbm, rssi_value()}
          | {:last_working_route,[ZWave.node_id()]}
          | {:transmit_speed, transmit_speed()}
          | {:transmit_time, non_neg_integer()}
          | {:route_changed, boolean()}

The response to a "transmission_stats" MQTT request would at a minimum contain the rssi info and last working route.

My proposal for this type, after chatting with you outside this issue, is:

@type transmission_stats() :: %{
    transmit_channel: non_neg_integer() | nil,
    ack_channel:  non_neg_integer() | nil,
    rssi_hops: [rssi_value()],
    rssi_4bars: 0..4 | :unknown,
    rssi_dbm: rssi_value() | nil,
    last_working_route: [ZWave.node_id()],
    transmit_speed: transmit_speed() | nil,
    transmit_time: non_neg_integer() | nil,
    route_changed: boolean() | nil
}

Where last working route is the last route known to work. If the packet gets a nack it should report the last route that worked, if it gets in ack it should report back the route it took.

Transmit time and speed are based on when the frame received an ack from the device.

When a field has an optional nil mean that upon a timeout or a nack request they will not have a value.

We can either still include those fields just default them to nil or make them optional in the typing. Which I think we could mark all fields as optional. This would look like:

@type transmission_stats() :: %{
    optional(:transmit_channel) => non_neg_integer() ,
    optional(:ack_channel) =>  non_neg_integer() ,
    optional(:rssi_hops) => [rssi_value()],
    optional(:rssi_4bars) => 0..4 | :unknown,
    # ... the rest
}

This way we only add the stat if it exists in the meta data of the packet. I am open to either way.

Oh, now I understand why this was a keyword list! It was because you're converting this from chain of TLVs from zipgateway, so you're basically getting a keyword list.

Now that I understand, I'm cool with keeping it a Keyword list. My second choice would be the map with the optional fields.

Closed by #525