Skip to main content

Z-Wave

Driver: zwave

The Z-Wave page is where you pair (include) and remove (exclude) Z-Wave devices, turn the nodes on the mesh into GEM zones, and wire each zone's buttons and feedback to specific Z-Wave values.

Open Z-Wave

The page lives under Integrations > Z-Wave. It talks to a USB Z-Wave stick plugged into the GEM server — Aeotec Z-Stick, Zooz ZST10, Nortek/GoControl HUSBZB-1 and similar. One stick is one controller device in GEM; everything on this page acts on the controller you select at the top.

Nothing here happens automatically

Including a node does not create a zone, and creating a zone does not make it controllable. A Z-Wave zone works only after you have (1) created it with a node:endpoint address, (2) mapped each button to a Z-Wave value in Command Mappings, and (3) mapped each piece of feedback in Response Mappings. All three steps are on this page, and the sections below follow that order.


Before you start — the controller device

Add the stick as a device

Go to Devices and click Add (when no controller exists yet, the Z-Wave page's empty state offers an Add a controller link that opens the same device editor in a modal and selects the new controller once saved).

FieldWhat to enter
NameLowercase name, e.g. zwave_controller.
Driverzwave.
TypeController or hub.
AddressThe serial path of the stick — /dev/ttyUSB0, /dev/ttyACM0, or a /dev/serial/by-id/... path.
Command SetRequired. Picking the driver auto-selects (and creates, on first use) a command set named zwave.
StatusOn.
ElevatedTurn on only if everything on this stick is sensitive. Most sites leave it off here and set Elevated on the individual lock or gate zone instead, so lighting on the same stick stays available to ordinary roles.

Address is the field the driver reads. The Device Attributes section also offers Serial Port (alt) (port), which is copied into Address when the controller connects — useful if a site already stores the path there. The Serial Path attribute in the same list is not used; leave it empty and put the path in Address.

USB serial path stability

On connect, the driver promotes a /dev/tty* address to its stable /dev/serial/by-id/... symlink so the controller survives replug and reboot reordering, and saves the new path back onto the device. If the configured path no longer exists (the dongle moved to a different USB port), it scans the by-id entries for a known Z-Wave descriptor — Silicon Labs HubZ -if00, Aeotec Z-Stick, generic Z-Stick, UZB, Zooz, Nortek, Sigma Designs — and points itself at the match. On a HubZ combo stick the -if00 interface is the Z-Wave radio and -if01 is Zigbee, which is why the match includes the suffix.

To switch this off, add a device attribute usb_auto_discover set to false. Worth doing only on a host with two identical Z-Wave sticks, where the wrong one could be picked up.

Security keys are minted for you

The first time the controller connects, GEM generates the four Z-Wave network keys (S0 Legacy, S2 Unauthenticated, S2 Authenticated, S2 Access Control) as random 32-character hex strings and stores them together in one encrypted, read-only device attribute named security_keys. You never type them in — the individual key fields listed under Device Attributes are not what the driver reads.

Re-keying breaks every secure pairing

If that attribute is deleted or replaced, every already-included secure device (locks especially) has to be excluded and re-included. Node pairings live with the stick and its own cache on the GEM server, not in GEM's database — replacing or re-flashing the stick means re-including every node.

The zone template — what makes a button work

A Z-Wave zone's buttons reach the stick only when the matching row in the controller's command set carries the template zone. On the controller device, open the Commands tab and check the Template column for the verbs you intend to use:

VerbTypical use
on, offSwitches, dimmers, outlets, fans
levelDimmer and shade position (also what the Light Dimmer slider sends)
high, medium, lowThree-speed fans
raise, lowerRamping controls
lock, unlockDoor locks
open, close, pulseGarage doors, gates, relay-driven loads
get_state, get_levelPresent in the command set; see the note below before mapping them

Rows that GEM filled in from the driver are flagged DRIVER in the Source column and are locked — the editor and the inline grid both refuse changes to a driver-managed name, template or arguments. So the templates need to be right before the rows become driver-managed:

  • Before the rows are locked: use Add/import command set (the small + next to the Command Set picker on the device), check the library list for a Z-Wave set, and assign it to the controller — imported rows keep the template they arrive with.
  • On a set whose rows are already locked, ask the AI Assistant to set the template on those command rows. It writes command rows directly and can overwrite existing ones, which is the way past the editor lock.

A verb whose Template is empty never reaches the Z-Wave dispatch: the button comes back with unknown command and nothing moves.

Mapped verbs write, they don't read

Everything in a zone's command map sends a value to the node — including get_state and get_level if you map them. Reading values back is what Response Mappings are for. Leave the get_* verbs unmapped.


Page layout

The controller strip runs across the top: the controller picker plus the enrollment, removal and reset buttons. Below it, the Z-Wave Nodes list sits on the left and Node Configuration fills the right. Until you pick a controller the page shows No Controller Selected; until you pick a node the right panel prompts you to select one.


Controller section

Controller picker

The dropdown lists every device using the zwave driver as [id] name (address). Choosing one loads its nodes, subscribes the page to live controller events, and enables the buttons beside it.

Enrollment, removal, reset

GroupButtonWhat it does
EnrollmentStartPuts the controller into inclusion mode after a confirmation prompt.
EnrollmentStopEnds inclusion mode. Disabled until inclusion is running.
RemovalStartPuts the controller into exclusion mode after a confirmation prompt.
RemovalStopEnds exclusion mode. Disabled until exclusion is running.
ResetSoft-resets the controller after a confirmation warning that active enrollments are interrupted. GEM disconnects from the stick, waits two seconds and reconnects — pairings are kept.

While inclusion is running, the removal Start button is disabled, and vice versa. Toasts report each state change as it happens.

Enrolling a new device

  1. Select the controller.
  2. Click Start under Enrollment and confirm.
  3. Put the physical device into pairing mode (usually a triple-tap on the paddle or a small button — check the manufacturer's instructions).
  4. Wait for the pairing to complete. A toast names the node when it is added, and the node list refreshes on its own.
  5. Click Stop when you are done adding devices.
Secure inclusion that needs a PIN cannot be completed from this page

The Start button runs the controller's default inclusion strategy. When a device asks GEM to grant security classes or to validate a DSK and enter the 5-digit PIN printed on the device, GEM records the request and carries on — it does not prompt you, so an S2 pairing that requires that confirmation will not finish. Devices that pair unauthenticated (most switches, dimmers, sensors) include normally.

If you need a specific strategy, run the start_inclusion command from the controller's Commands tab with a strategy argument of default, smart_start, insecure, security_s0 or security_s2 — see Maintenance commands below.

Removing a device

  1. Select the controller.
  2. Click Start under Removal and confirm.
  3. Trigger the exclusion sequence on the physical device.
  4. A toast names the node when it is removed and the list refreshes.
  5. Click Stop to leave removal mode.
tip

Exclusion works on devices that were paired to a different controller, so it doubles as a factory reset before re-enrolling gear pulled from another system.


Nodes panel

The left panel lists every node the controller knows about, as [node id] manufacturer description. The reload icon in the panel header re-reads the list from the stick. Nodes the controller has not yet interviewed show as Unknown with no description — reload after a minute, or run refresh_node_info for that node.

Click a single node to load it. The list allows multi-select, but only one node at a time can be configured; selecting more than one shows a warning and loads nothing.

Selecting a node reads its full value list from the stick, which is what fills the Endpoint and Command Class dropdowns, and lists the zones already created against that node.


Node Configuration panel

Zone Management

Existing Zones lists the zones already created on this controller whose address begins with the selected node id. Picking one loads its subsystem, endpoint and control type, locks those three fields, and reveals the Mappings tabs for that zone.

Open opens the selected zone's full editor — attributes, programming, history — in a modal, so the node selection and any mapping work in progress on this page survive the detour.

Delete removes the selected zone. It asks for confirmation first, then deletes the zone, every attribute on it (including its command and response maps) and every UI zone assignment pointing at it.

To create a new zone for the node:

FieldWhat to enter
SubsystemRequired. The subsystem the zone belongs to — lights, shades, doors, climate, and so on.
EndpointRequired. Pick from the endpoints this node actually exposes. Single-load devices have only 0; a two-relay module or a dual outlet exposes 1 and 2 as well.
Control TypeThe zone control the UI should render — light_dimmer, light_switch, door_lock and so on. The list offers every control already in use on the site, and you can type a new one.

Click Create Zone. GEM asks for the zone name, pre-filled from the node's manufacturer and model, and creates an enabled zone whose address is node:endpoint (for example 12:0) and whose device is this controller.

The colon is not optional

A Z-Wave zone address must be node:endpoint. An address without the colon is logged as invalid when the controller connects and the zone is never controllable. Zones created on this page always get it right; zones created by hand on the Zones page do not.

Command Class Configuration

This section is where you find the specific Z-Wave value behind a function, and test it before you map it.

Select the Endpoint first. The Command Class dropdown only lists values belonging to the endpoint chosen above it, so while Endpoint is empty the dropdown is empty too. Each entry reads [class number] Class Name property (endpoint n) — for example [38] Multilevel Switch currentValue (endpoint 0).

Choosing a value reads its metadata from the node, and the controls that appear depend on what came back:

Writable values get a Value box and a Test Set button. The box adapts to the value's type — a true/false dropdown for boolean, a list of named states for values with a state table (thermostat modes, lock modes), or a plain typed input for numbers and strings. Test Set writes the value to the node immediately.

Read-only values show Read-only value and a Test Get button, which reads the current value and prints it beside the label.

tip

Test before you map. If Test Set does not move the load, the mapping will not either — that is a Z-Wave problem (wrong value, sleeping device, out of range), not a GEM one.

Mappings

The Command Mappings and Response Mappings tabs appear once a zone is selected under Zone Management. Between them they write the two things the driver needs to run the zone.

Command Mappings

A command mapping ties one GEM verb to one Z-Wave value plus the value to send.

  1. Select the Endpoint and then the Command Class value in the section above.
  2. If the value is writable, enter the Value to send for this verb — 99 for a dimmer's on, 0 for its off, and leave it as-is for level, where the slider supplies the number.
  3. Pick the Zone Command — the dropdown lists the verbs in this controller's command set that carry the zone template.
  4. Click Map Command.

Saved mappings appear under Mapped Commands as verb ← Class property value, each with two icons: the remote icon sends that verb to the zone as a live test, and the delete icon removes the mapping after a confirmation.

Numbers and true/false values typed into the Value box are converted to the type the node reported, so the map holds 99 rather than "99". Each saved entry also carries the value's metadata, which is what lets GEM clamp a slider: a level or setpoint argument above the value's own maximum is reduced to that maximum before it is sent. That is what keeps a UI slider sending 100 working against a Multilevel Switch, which tops out at 99 (255 on that class means "restore the last level", not "full").

Response Mappings

A response mapping ties one zone attribute to one Z-Wave value, so the zone reflects what the device reports.

  1. Select the Endpoint and Command Class value in the section above.
  2. Enter or pick the Attribute Namestate, level, temperature, battery, and so on. The list offers every zone attribute name already in use; you can type a new one.
  3. Turn Map Values on and use the Value Mapping editor to translate raw readings into the words the UI expects — 255on, 0off, 23closed.
  4. Click Map Response.

Saved mappings appear under Mapped Responses with their value translations underneath, each with a delete icon.

Turn Map Values on before saving

Map Response only completes while the Map Values switch is on — with the switch off the save does not go through and no toast appears. If a response mapping never shows up in the list, that is why. Leave the translation table empty if you don't need one; the switch itself is what matters.


How a mapped zone behaves

Commands out

Pressing a button on a UI, running a macro step or firing a trigger sends the verb to the zone. GEM looks the verb up in the zone's command map and writes the mapped value to the mapped Z-Wave value. It also records what it sent on the zone as an attribute named after the verb — a level command leaves a level attribute, an on command leaves an on attribute. Those are a record of the last command, not device feedback; feedback comes from response mappings.

Two error replies tell you exactly what is missing:

  • missing command map — nothing has been mapped for this zone at all.
  • command not mapped — the zone has a command map, but not for the verb you pressed.

The node comes from the zone, not from the payload. A zone command takes its node and endpoint from the zone's own node_id:endpoint address, so a node_id argument sent alongside is overwritten rather than honoured — a benign zone's command map can never be applied to a different node on the mesh. This holds for every caller, macros and triggers included: the command map being applied belongs to the zone, so aiming it at another node would write one zone's value mapping to different hardware. Ordinary traffic is unaffected: a zone command has no reason to carry a node id.

When a payload does name a different node, the override is logged as "zwave: ignoring caller node_id … is node …" with both node ids. Macro step and script payloads are stored as JSON, so that log line is the practical way to find a saved automation still aiming at the wrong node — search Logging for it after a zone is re-addressed.

Feedback in

Feedback is polled, not pushed. Reports the device sends on its own are logged but do not update the zone. Instead, once the controller connects, GEM walks each zone's response map in turn — one value per second — reads each value from the node, applies the value translation, and writes the result onto the zone attribute when it changed. The pass then repeats after the controller device's status_interval attribute in milliseconds, defaulting to 3000 (3 seconds).

Two consequences worth planning around:

  • Add status_interval on a large mesh. With one read per second per mapped value, a stick with many mapped zones spends real time on each pass. Raising the interval on the controller device spaces the passes out.
  • Polling starts only when the controller connects. New response mappings stay dark until the controller reconnects. Finish the whole batch of mappings, then reload the controller device once from the Devices page.

open, close and pulse

open and close do not write a value directly — they are built for garage doors and gates driven by a momentary contact:

  • GEM reads the zone's state attribute first and acts only when it disagrees with the request, so close on an already-closed door does nothing. If state is unknown, GEM goes ahead anyway. Map state in Response Mappings if you want that check to work.
  • The pulse itself sends the mapped value, waits, and sends it again. The wait comes from the verb's delay argument in milliseconds; anything under 2000 is raised to 2000 to give an opener time to settle, and leaving it empty gives no wait at all — always supply a delay.
  • The zone attribute normally_closed reverses the order of the two writes.
Do not use open/close on shades

A shade motor is positioned, not pulsed. Map level for shades, and if the UI needs open/close buttons, set the zone's open_action and close_action attributes to re-dispatch level at 99 and 0. The AI assistant's shade profile below does exactly that.


Bulk node mapping with the AI Assistant

The Mappings tabs above save one entry per round trip — pick a node, refresh its value IDs, pick one, read its metadata, pick the verb, type the value, save; then do the response side. That is the right tool for one odd node. A single dimmer is five of those loops, a multisensor is more, and a typo in a value ID surfaces only as command not mapped when the button is pressed.

For a batch, the AI Assistant has a map_zwave_zones skill — the Z-Wave sibling of map_bacnet_points, map_modbus_points, map_mqtt_topics, map_knx_group_addresses and map_opc_ua_points. Include the nodes first (enrollment above), then describe them:

Map node 12 as the kitchen island dimmer, node 8 as the front door lock, and nodes 14 and 15 as the bedroom multisensors.

It creates (or updates) one zone per node on the controller, builds the node:endpoint address the driver requires (an address without the colon is never controllable), and writes both mapping attributes from a device-class profile:

ProfileCommand classCommandsReports
switchBinary Switch (37)on / offstate
dimmerMultilevel Switch (38)on / off / levellevel, state
fanMultilevel Switch (38)on / off / low / medium / high / levellevel, state
shadeMultilevel Switch (38)level, plus open_action / close_action overrideslevel, state
lockDoor Lock (98)lock / unlockstate (full lock-mode map), battery
sensornone (read-only)from sensors

What it handles for you:

  • Levels are clamped at 99. The Multilevel Switch class tops out at 99 — 255 means "restore last level", not a position — so a UI slider sending 100 still works.
  • The shade trap. Native open/close go through the momentary pulse described above, which would never position a shade motor. The shade profile leaves those verbs out of the command map and wires the zone's open_action / close_action overrides to re-dispatch level at 99 / 0 instead.
  • Metadata on every command entry. Generated entries always carry the value's metadata, exactly as entries saved from this page do — that is what the clamping relies on.
  • Extra telemetry. Any profile can add sensors shorthands — battery, temperature, humidity, illuminance, ultraviolet, motion, contact, tamper, leak, smoke, co, and the legacy Binary Sensor forms. Meter (class 50) power/energy must be given explicitly, because its property key is a computed code that differs per device — read it off the node's value list in Command Class Configuration. Battery is included by default on the lock and sensor profiles.
  • Validation before any write. The device must be a Z-Wave controller, node IDs must be 1-232, and duplicate node:endpoint pairs are rejected in-batch and against existing zones on the controller (two zones on one address means the second silently shadows the first). A mid-batch failure deletes every zone it created and restores every attribute it touched. It also warns when a mapped verb has no zone-template row in the controller's command set — only those rows route into the driver's zone dispatch.

Reloading is deliberately different from the other point-mapping skills. Mapped zones are always reloaded, which is all a command needs — buttons work immediately. The controller itself is not reloaded unless you ask (reload_device), because the response pollers only start when the driver connects, and reloading a Z-Wave controller restarts the serial driver and re-interviews the mesh. The consequence: attribute feedback stays dark until the controller reconnects. Map the whole batch, then reload the controller once.

Ask for a dry run first whenever the assistant inferred profiles from node names — it returns the resolved address, profile, verbs and reports per zone and writes nothing. The cap is 60 zones per call. Inclusion itself stays on this page — the assistant maps nodes that are already on the mesh, it does not pair them. Per-node raw command_map / response_map entries can be passed for anything a profile doesn't describe, and merge over the profile output.


Maintenance commands

The page exposes inclusion, exclusion and soft reset. Everything else the controller can do runs from the controller device's Commands tab: open Devices, click the remote icon on the controller row, pick the controller in Test Device, then click the remote icon on the command row. Commands that take arguments open a form first; replies and device chatter appear in the Device Console below the grid.

CommandArgumentsWhat it does
get_nodesFull record for every node: id, name, location, manufacturer, model, ready flag, status, whether it sleeps, whether it is securely paired, beaming support, protocol and firmware versions.
get_defined_value_idsnode_idEvery value the node exposes — the same list the Command Class dropdown is built from.
get_value / set_valuenode_id, value_id, valueRead or write one value directly. Elevated sessions only — see the note below.
get_value_metadatanode_id, value_idType, range, writability and state table for one value.
get_endpointsnode_idEndpoint list with the command classes each one supports.
get_node_confignode_idThe device configuration file the controller matched to this node.
refresh_node_infonode_idRe-interviews the node. Use on a node stuck at Unknown. Elevated sessions only.
ping_nodeaddressRound-trip check against a node.
get_node_neighborsnode_idWhich nodes this one can hear — the practical way to find a routing hole.
heal_nodenode_idRebuilds routes for one node. Elevated sessions only.
start_healing_network / stop_healing_networkRebuilds routes mesh-wide. Run it after adding or moving mains-powered nodes, and expect it to take a while on a large mesh. Elevated sessions only.
start_inclusionstrategyInclusion with an explicit strategy: default, smart_start, insecure, security_s0, security_s2. Elevated sessions only.
soft_reset_controllerSame as the page's Reset button — reconnects to the stick, keeps pairings. Elevated sessions only.
hard_reset_controllerWipes the stick. Every node must be re-included afterwards. Elevated sessions only.

Two rows in that list are not finished: refresh_values and poll_value appear in the command set but have no implementation behind them and answer unknown command. Use refresh_node_info to re-read a node, and response mappings for ongoing values.

Commissioning commands require an elevated session

get_value / set_value name a node and a raw value_id with no zone in between, so no command map confines what they reach — that is the Door Lock write in its most direct form.

Controller lifecycle is gated the same way: start_inclusion, stop_inclusion, start_exclusion, stop_exclusion, start_healing_network, stop_healing_network, heal_node, refresh_node_info, toggle_radio, soft_reset_controller and hard_reset_controller. These change the mesh itself rather than any one zone, and nothing else confines them — the address rule has no address to check when the payload names no node, and most sites leave Elevated off on the controller so ordinary lighting on the same stick stays usable (see the device table above). So the command list is the only thing standing between a guest tablet and a factory reset that unpairs every lock on the mesh.

All of them answer not authorized: this command requires an elevated session for a non-elevated caller (a guest tablet, kiosk or PIN wall panel). Reads — get_nodes, get_endpoints, get_node_config, get_node_neighbors, ping_node, get_value_metadata, get_defined_value_ids — and every mapped zone command are unchanged, as are macros, triggers, schedules and drivers. See Roles → Elevated devices and macros.

node_id is also treated as a hardware address by the central address confinement, so a non-elevated caller cannot aim a command at a node the account has no zone for.


Real-time updates

While a controller is selected, the page listens for controller events and reacts to them:

EventWhat you see
node_addedToast naming the node; the node list refreshes.
node_removedToast naming the node; the node list refreshes.
inclusion_started / inclusion_stoppedToast; the enrollment buttons swap enabled state.
exclusion_started / exclusion_stoppedToast; the removal buttons swap enabled state.
inclusion_failed / exclusion_failedError toast; the buttons reset so you can retry.
heal_network_doneToast confirming a network heal finished.

A heal in progress reports quietly without a toast, so a mesh-wide heal looks silent until it completes.


Troubleshooting

Enrollment fails

  1. Confirm inclusion is actually running — Start was clicked and the toast appeared.
  2. Confirm the device is in pairing mode (manufacturer instructions).
  3. Move the device within about 30 feet of the controller for the initial pairing; you can relocate it afterwards.
  4. Exclude the device first, then re-enroll — this clears a pairing to a previous controller.
  5. If the device demands DSK/PIN validation, it will not finish from this page. See the secure-inclusion warning above.

The node list is empty or a node shows as Unknown

  1. Confirm the controller device is enabled and connected — the address must point at a serial path that exists.
  2. Use the reload icon in the Z-Wave Nodes header.
  3. Run refresh_node_info for the node. Battery devices must be awake for this to succeed; press the device's button first.

A button does nothing, or the reply is an error

ReplyFix
unknown commandThe verb's row in the controller's command set has no zone template. See "The zone template" above.
missing command mapThe zone has no command mappings yet.
command not mappedThe command map has no entry for that verb — map it in Command Mappings.
unknown zone addressThe zone's address is not a node:endpoint pair on this controller.
Nothing at allTest the value directly with Test Set. If that does not move the load, the mapped value is wrong for the device.

Values are not updating

  1. Confirm the attribute is mapped in Response Mappings — feedback only comes from polling those entries.
  2. Reload the controller device. Response mappings added since the controller last connected are not being polled yet.
  3. Battery devices only answer while awake, so their attributes update on their own reporting rhythm rather than on the poll cycle.
  4. Check the value translation under Map Values — a raw reading with no translation is written through as-is, so a UI expecting on/off will not light up for 255/0.
  5. Confirm the attribute type matches what the device reports.

The device responds slowly or intermittently

  1. Check get_node_neighbors for the node — a node with no mains-powered neighbour is a routing hole.
  2. Run start_healing_network after adding or moving mains-powered devices.
  3. Raise status_interval on the controller if a large mesh is being polled continuously.
  4. Soft-reset the controller if communication remains unreliable; the Reset button keeps pairings.
  • Devices - Z-Wave controller device configuration
  • Zones - Zone configuration
  • Command Sets - Zone command definitions and the zone template
  • Attributes - Editing zone and device attributes by hand
  • AI Assistant - map_zwave_zones bulk node mapping