Helvar Router (HelvarNet)
GEM drives Helvar 900-series lighting routers (910, 920, 930, 940) over HelvarNet, Helvar's plain-ASCII TCP protocol. Each DALI load or Helvar group becomes a GEM zone with level, on/off, and scene recall, and device-addressed zones are polled for their real bus level.
This is the integration to reach for on a commercial Helvar site — offices, airports, education — where the lighting is already commissioned in Helvar Designer and the ask is to expose a few groups and scenes on GEM dashboards, macros, and schedules.
This driver drives a commissioned workgroup. It does not commission the DALI bus, create groups, or edit scene tables — that stays in Helvar Designer.
Prerequisites
- A commissioned Helvar workgroup with known device addresses and group numbers. Export or screenshot them from the Designer project — GEM has no way to invent them.
- TCP 50000 reachable from the GEM controller to the router. HelvarNet is enabled by default on 900-series routers.
- A free HelvarNet session on the router. Routers cap concurrent sessions, and a Designer connection left open can consume the slot GEM needs.
HelvarNet has no authentication. Anything that can open TCP 50000 can drive the lighting. Keep routers on a controlled VLAN and do not expose the port beyond the building network.
Setup
- Add a device with driver
helvar_net. - Set
ipto the router's LAN IP. Leaveportat50000unless the site has remapped it. - (Optional) Set
fade_time— the default fade applied when a command does not pass one, in centiseconds (100= 1 second). - Save and enable. The driver opens the socket, starts a keepalive query, and begins polling any device-addressed zones.
- Walk the workgroup from the script console:
get_clusters— cluster ids on the workgroup.get_routerswithcluster— router ids in that cluster.get_deviceswithaddressset tocluster.router.subnet— device types and addresses on that subnet.
- Create a zone per load or group and set
zone.address(see below). - For zones that should come on at less than full output, set the zone's
on_level.
Attribute Reference
Device
| Name | Type | Required | Default | Notes |
|---|---|---|---|---|
ip | string | yes | — | Router LAN IP. |
port | int | no | 50000 | HelvarNet TCP port. |
fade_time | int | no | 100 | Default fade in centiseconds. |
on_level | int | no | 100 | Level (%) written by on when the zone has no override. |
status_interval | int | no | 30000 | How often device-addressed zones are re-read, in ms. |
query_timeout | int | no | 5000 | How long to wait for a router reply, in ms. |
ping_interval | int | no | 60000 | Keepalive query cadence, in ms. |
Zone
| Name | Type | Required | Default | Notes |
|---|---|---|---|---|
address | string | yes | — | Device address or group (see below). |
on_level | int | no | — | Per-zone override for the level on writes. |
fade_time | int | no | — | Per-zone override for the default fade. |
Zone Address Format
Two forms are accepted:
| Form | Example | Meaning |
|---|---|---|
| Device | 1.2.1.5 | cluster.router.subnet.device |
| Group | G12 | Helvar group 12 (group:12 and g12 also parse) |
A Designer address column often shows only the subnet.device tail — the cluster and router numbers must be prepended for GEM.
Group zones send group-wide commands and are the right choice for "the whole open-plan area". Device zones are the right choice for anything that needs true state, because only device addresses are polled.
Commands
| Command | Args | Description |
|---|---|---|
on | address | Direct level to the zone/device on level. |
off | address | Direct level to 0. |
set_level | address, level, fade | Direct level 0–100, optional fade in centiseconds. |
recall_scene | address, block, scene, fade | Recalls a scene within a block. |
get_level | address | Queries the current load level of a device address. |
get_clusters | — | Lists cluster ids. |
get_routers | cluster | Lists router ids in a cluster. |
get_devices | address | Lists device types and addresses on cluster.router.subnet. |
query | command, address, group, params | Issues an arbitrary HelvarNet query by command id. |
raw_command | command | Writes a complete frame verbatim. |
Wire format
Frames are readable, which makes this protocol easy to troubleshoot from the device log:
>V:2,C:14,L:50,F:100,@1.2.1.5# direct level 50% over 1s on device 1.2.1.5
>V:2,C:13,G:12,L:0,F:100# direct level 0% over 1s on group 12
>V:2,C:12,B:1,S:3,F:200,@1.2.1.5# recall block 1 scene 3 over 2s
?V:2,C:152,@1.2.1.5# query the load level
?V:2,C:152,@1.2.1.5=75# …and the router's reply
> is a command, ? is a query, ! is an error, and every frame terminates with #. Replies echo the query and append =<answer>, which is how this driver matches an answer to the request that asked for it.
Reaching unmodeled commands
HelvarNet has a large command set. This driver hardcodes only the ids it can stand behind: the four control writes (11, 12, 13, 14), the load-level query (152), and cluster/router/device discovery (101, 102, 104). Everything else — descriptions, group membership, scene names, emergency test functions — goes through the passthroughs with the id taken from the HelvarNet reference manual:
command: query
args: {command: 106, address: "1.2.1.5"}
command: raw_command
args: {command: ">V:2,C:14,L:100,F:0,@1.2.1.5#"}
raw_command waits for a reply when the frame starts with ? and is fire-and-forget otherwise.
Known Limitations
- Write commands are fire-and-forget. HelvarNet only acknowledges a
>command when the frame explicitly asks for one, so a successful send means the frame reached the router — not that the load moved. Read it back withget_levelwhen confirmation matters. - Group zones are not polled. A group has no single load level, so a
G12zone reflects the last level GEM wrote rather than bus truth. Bind anything that needs real feedback to a device address. - Units bite. Levels are percent (0–100); fades are centiseconds. A fade passed in milliseconds runs ten times too long.
- Discovery is a manual walk. There is no single "list everything" call — clusters, then routers, then per-subnet device queries. Subnets are typically 1–4 per router.
- No scene-table or group-membership caching. GEM does not know which loads belong to a group or what a scene contains; that stays in Designer.
- Unverified command ids are deliberately absent. Rather than guess at ids for descriptions or emergency testing, those are left to
query/raw_command. If you verify an id against real hardware, it is a small change to promote it to a named command.
Troubleshooting
| Symptom | Check |
|---|---|
| Socket connects then drops repeatedly | Routers cap concurrent HelvarNet sessions. Close any Designer or third-party connection holding one. |
| Commands send but nothing moves | Check the address form — 1.2.1.5 is cluster.router.subnet.device, and Designer often shows only the tail. |
| Queries always time out | Watch the device log for a ! frame; the router is answering with an error rather than a value. Also confirm query_timeout is not shorter than the router's response time on a busy bus. |
| Zone level never updates | Group-addressed zones are not polled by design. Rebind to a device address. |
| Lights fade far too slowly | A fade was passed in milliseconds. Divide by 10 — F is centiseconds. |