Runtime DALI lighting control for the RESI-DALI-SIO and RESI-DALI-ETH Modbus-DALI gateway. Per-gear dimming for up to 64 control gears, 16 broadcast groups, and per-gear DALI 1.0 status, lamp/power-failure and min/max-level diagnostics over Modbus RTU.
ResiModbus RTU80 devicesRevision 1.3Last updated: November 15, 2026
Import into the TapHome appHardware › Modbus › Add from template
The Resi DALI template is the runtime operational counterpart to the Resi Dali - Configuration commissioning tool. It connects TapHome to a fully addressed DALI lighting bus through the RESI-DALI-SIO or RESI-DALI-ETH Modbus-DALI gateway and exposes day-to-day control for up to 64 individually addressed DALI control gears (short addresses 0–63) and 16 DALI broadcast groups (0–15), plus per-gear DALI status, control-gear-failure and lamp-failure diagnostics.
Communication with the gateway uses Modbus RTU at 9600 baud 8N1. Brightness writes go to H:510 LAMP LEVEL (per-gear) and H:520 GROUP LEVEL (per-group); per-gear configuration commands and queries are tunnelled through H:511 LAMP COMMAND / H:512 LAMP COMMAND + REPEAT, with the gateway’s H:550 DALI STATUS register polled for response readiness.
This template assumes DALI short addresses are already programmed on the bus. If gears are still un-addressed, use the sibling Resi Dali - Configuration template (or the manufacturer’s free MODBUSConfigurator / DCA tool) to run the DALI 2.0 random-addressing wizard first — see Relationship with the commissioning template below.
The RESI-DALI-SIO (RS-485) and RESI-DALI-ETH (Ethernet) are DIN-rail master gateways that sit between a serial/Ethernet host and a DALI lighting bus. The SIO ships in a CEM17 housing (17.5 × 90 × 56.4 mm) and the ETH in a wider CEM35 housing (35.8 × 90 × 56.4 mm) to fit the RJ45 connector. Neither gateway powers the DALI bus by itself — a companion DALI bus power supply (RESI-DALI-PS or any compliant 200 mA DALI PSU) is mandatory.
Connecting the RESI-DALI-SIO (RS-485)
Terminals on the left side of the RESI-DALI-SIO (top → bottom): GND, +12..48V=, RS485 DATA+ (A+), RS485 DATA- (B-), RS485 GND, RS232 TX, RS232 RX, RS232 GND. The DALI bus terminals on the opposite side are D+ / N/C / D- (3-pin USLIM block, the middle N/C pin stays unconnected).
For a TapHome installation use the RS-485 interface:
RS485 DATA+ (A+) → A+/D+ on the TapHome RS-485 bus
RS485 DATA- (B-) → B-/D- on the TapHome RS-485 bus
RS485 GND → GND on the TapHome power supply (recommended for stable communication)
+12..48V= / GND → 12–48 V DC primary power
Connecting the RESI-DALI-ETH (Ethernet)
The Ethernet variant has the same DALI bus terminals (D+ / N/C / D-) and primary power inputs (GND, +12..48V=), plus a single RJ45 connector for 10/100 Mbit Ethernet. Factory-default IP settings are 192.168.0.191 / 255.255.255.0 / 192.168.0.1 with Modbus Unit ID 255; the embedded web UI uses credentials RESI / RESI.
Because this is a Modbus RTU template, TapHome does not talk to the RESI-DALI-ETH via native Modbus/TCP. Use it instead in transparent RTU-over-Ethernet mode, or place the SIO behind a serial-to-IP bridge (Moxa NPort, USR-TCP232) — see Configuration → RTU-over-TCP setup below.
DALI bus power supply (RESI-DALI-PS)
The RESI-DALI-PS delivers up to 200 mA on the DALI bus (short-circuit current ~225 mA, bus voltage typically 14–18 V) and supports up to 64 DALI 1.0 ballasts or DALI 2.0 control gears on a single line. Primary side accepts the same 12–48 V DC supply as the SIO/ETH unit. The gateway and PSU tap into the same D+ / D- pair — the PSU energises the bus while the gateway reads and writes DALI frames.
Three LEDs on the PSU help during fault diagnosis: POWER (primary 12–48 V OK, always on in normal operation), DALI (flashes briefly during DALI bus traffic), ERR (steady on PSU fault, DALI short circuit or bus overload — must be off in normal operation).
DALI bus topology
A DALI line imposes a few hard constraints that directly affect runtime stability:
Conductor cross-section
Max DALI cable length
1.5 mm²
300 m
1.0 mm²
238 m
0.75 mm²
174 m
0.5 mm²
116 m
The limit comes from the maximum permitted 2 V voltage drop across the DALI cable. Other rules:
Maximum 64 DALI 1.0 ballasts and up to 64 DALI 2.0 control gears per bus (separate short-address spaces).
Tree topology only — no rings, no loops.
Actual gear count also depends on the PSU current rating (typically 200 mA on the RESI-DALI-PS; budget ~2 mA per gear plus reserve).
RESI-DALI-PS (or equivalent DALI PSU) is mandatory. Without it the gateway cannot drive the bus and every per-gear read will time out as “Gear not responding!”. If a second PSU is added on a long line, insert a DALI choke or split the bus into galvanically separate segments.
Host serial parameters on the RESI-DALI-SIO are selected by a 4-position DIP switch on the module. The TapHome template is fixed at 9600 baud 8N1, so the DIP switches must match.
FLASH register H:65221 is honoured — required if a non-default Slave ID was programmed during commissioning
ON
Hardware fallback — Unit ID is forced to 255, the FLASH value is ignored
DIP3 is a product-specific reserved bit; leave it in the factory position. Parity is fixed at None and stop bits at 1 (8N1 frame format) for the DIP1/DIP2 baud-rate combinations selected above.
RS-485 termination: terminate the bus with 120 Ω at both ends. TapHome Core provides one termination on its BUS terminals; if the RESI gateway is the last device on the line, add a discrete 120 Ω resistor across A+ / B- on its RS-485 terminals.
Slave ID
Factory-default Modbus Unit ID is 255 (FLASH register H:65221 reads 0xFFFF, which the gateway clamps to 255). The template exposes a module-level service attribute Slave ID that reads back this register, so the configured address can be verified after import.
Changing the Slave ID is a commissioning concern handled by the sibling Resi Dali - Configuration template — this runtime template intentionally does not write to H:65221 or trigger a software reset, so it can be left active in the project without risk of accidental gateway reconfiguration.
RTU-over-TCP setup
Because the template uses a Modbus RTU connection, an IpAddress import parameter is also offered for installations where TapHome reaches the gateway through a serial-to-IP bridge (Moxa NPort, USR-TCP232) or through the RESI-DALI-ETH in transparent RTU-over-Ethernet mode. In that case point IpAddress at the bridge / ETH unit IP and keep all other settings identical to the RS-485 variant. For pure Modbus/TCP a TCP-based template would be more natural — this Modbus RTU template specifically expects framed RTU traffic.
Only one Modbus master at a time. Neither DALI nor Modbus RTU arbitrate between concurrent masters. If a PLC, BMS or PC tool (for example MODBUSConfigurator) is also polling the gateway, gear queries will collide and TapHome will report sporadic “Gear not responding!” errors.
The same Dali.xml definition ships with the RESI gateway as two complementary TapHome templates that operate on different lifecycle phases of the same hardware:
Template
Phase
What it does
When to use
Resi Dali - Configuration (resi-dali-daliconfig)
One-off commissioning
DALI 2.0 random-addressing wizard, per-address device-type probe, broadcast ON/OFF sanity tests, Reset / Delete / Change short address, Set Slave ID, Reset Gateway
New installation: assign short addresses 0–63 to control gears, verify which addresses are populated
Resi DALI (resi-dali-dali, this template)
Daily runtime control
Per-gear dimming (64 gears), group dimming (16 groups), per-gear DALI 1.0 diagnostics, group membership management
After commissioning: end-user lighting control
Typical project flow:
Wire and power the DALI bus (RESI-DALI-PS) and the gateway.
Import the Resi Dali - Configuration template, run the module action Reset Short Addresses (Confirm = Yes), then select Start on the Find New Devices wizard — it steps through Scan Short Address → Set SEARCHADDR → Check → PROGRAM SHORT ADDRESS on its own until it stops on Finish, then close the session with TERMINATE. Verify with Gear 0..63 and Turn On / Off All Lamps.
Remove the Resi Dali - Configuration module from the project.
Import the Resi DALI template (this one) for runtime control. Map the Gear N and Group N devices to TapHome scenes, schedules and rules.
Both templates can also coexist temporarily — e.g. when adding a new gear to a live installation — but only one should send Modbus traffic at a time. The runtime template intentionally omits gateway reconfiguration actions (Reset Gateway, Set Slave ID, broadcast ALL LEVEL) so it can stay in the project without risk of overwriting commissioning settings.
The manufacturer’s free MODBUSConfigurator DCA tool (Windows, available from the RESI website) can also be used for commissioning instead of the Resi Dali - Configuration TapHome template. The runtime Resi DALI template works the same way regardless of which tool was used to assign short addresses.
The template exposes 80 DALI devices in TapHome, organised in two parallel groups: 64 Gear dimmers (one per DALI short address) and 16 Group dimmers (one per DALI group). One module-level service attribute completes the picture.
Per-gear dimming — Gear 0 … Gear 63
Each of the 64 service devices Gear 0, Gear 1, … Gear 63 is a TapHome dimmer that targets a single DALI control gear at the matching short address. Brightness writes go to H:510 LAMP LEVEL (TapHome 0–100 % is scaled linearly into the DALI arc-power range bounded by the gear’s own MIN LEVEL and MAX LEVEL); the actual level is read back from H:511 via the DALI QUERY ACTUAL LEVEL (0xA0) command and rescaled into 0–100 %.
When the template imports a gear, an init script first probes the gear with QUERY STATUS (0x90); any reply byte proves the gear is present and is stored as its status. A 0x8000 “no answer” response marks the gear as not responding (for a random 1–60 s) and emits “Gear not responding!” in the TapHome log. If the gear answers, the init script then reads QUERY MIN LEVEL (0xA2) and QUERY MAX LEVEL (0xA1) and stores the results in internal state for the periodic readscript.
Every query is guarded against stale and corrupted answers: before each query the template reads away an unread answer left in H:511, so it is not taken for the answer to the new query. A level answer that is not a valid level (0xFF, 0x20FF bus collision, 0x8000 no answer) or lies between 1 and the gear’s MIN LEVEL is rejected and the last level is kept, and a changed level is accepted only after a second equal read. The level service attributes show -- instead of an invalid value.
Each gear exposes 12 service attributes that read DALI 1.0 / 2.0 query commands on demand:
Service attribute
DALI command
Reports
Short Address
(internal)
The short address (0–63) targeted by this device — fixed at template-import time
Device Type
QUERY DEVICE TYPE (0x99)
DT{n} (e.g. DT0 fluorescent, DT6 LED, DT8 colour / tunable white) or -- when no answer. A gear with several device types answers 0xFF (MASK); the template then lists them with QUERY NEXT DEVICE TYPE (0xA7), e.g. DT6, DT8, or shows MASK when no type is returned
Physical Min Level
QUERY PHYSICAL MIN LEVEL (0x9A)
Hardware-imposed minimum dimming level in %
Max Level
QUERY MAX LEVEL (0xA1)
Configured upper bound used when scaling 0–100 % to DALI arc power
Min Level
QUERY MIN LEVEL (0xA2)
Configured lower bound used when scaling 0–100 % to DALI arc power
Power Up Level
QUERY POWER ON LEVEL (0xA3)
Brightness restored after DALI bus power is re-applied
System Failure Level
QUERY SYSTEM FAILURE LEVEL (0xA4)
Brightness adopted when the bus loses communication for >500 ms
Groups
QUERY GROUPS 0-7 (0xC0) + QUERY GROUPS 8-15 (0xC1)
Comma-separated list of DALI groups the gear belongs to (None or e.g. 0,3,7)
DALI Status
QUERY STATUS (0x90)
Decoded status byte with its raw value: OK when no bit is set, otherwise the set flags — gear failure, lamp failure, lamp on, limit error, fade running, reset state, missing short address, power cycle — e.g. lamp on (0x04). A failure present since the gear’s first answer is marked not raised: … reported since start
fade time {n} ({t} s), fade rate {n}; fade time off when it is 0, or extended 0x.. when the gear uses an extended fade time instead
DALI Version
QUERY VERSION NUMBER (0x97)
DALI-1 or DALI-2 {major}.{minor}, followed by the raw value in brackets
Bus statistics
(internal counters)
Counters since start: queries, stale answers read away, no answer, collisions, rejected levels
The periodic readscript on each gear reads the current arc level (0xA0) and polls QUERY STATUS (0x90) at least once every 60 read cycles. Bit 0 of the status byte raises “Control gear failure!” and bit 1 raises “Lamp failure!” — surfaced as TapHome warnings/errors so a failing fluorescent tube or a tripped LED driver shows up in the activity log without manual polling. A changed failure bit is taken only after a second equal read, and a lost answer is asked once more before the gear is reported as “Gear not responding!”. Failure bits that a gear reports in its first answer are treated as its permanent state: they are shown in DALI Status but not raised, until the bit clears — a later failure is then raised again. Power failure is not raised as an error; the status bit appears in DALI Status as power cycle.
Per-gear configuration actions
Five service actions on every Gear N device write DALI configuration commands (auto-repeated within 100 ms via H:512 LAMP COMMAND + REPEAT as required for non-volatile DALI commands):
Add to Group (parameter Group ID 0–15) — sends ADD TO GROUP (0x60+grp) so the gear joins the chosen DALI group and will obey subsequent broadcast group writes.
Remove from Group (parameter Group ID 0–15) — sends REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings — sends DALI RESET (0x20); restores all NVM parameters of the gear (max/min/power-on/system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels — captures the current arc power and stores it as Power On Level and System Failure Level, in sequence: STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D), each with a 10 ms gap.
Disable fading (no parameters) — loads 0 into the DALI data transfer register (0xA300 written to H:541) and stores it in the gear as fade time (0x2E) and extended fade time (0x30), each with a 100 ms gap, so level changes take effect without fading. The current values are shown in the Fade attribute.
Group dimming — Group 0 … Group 15
Each of the 16 service devices Group 0, Group 1, … Group 15 is a write-only TapHome dimmer that broadcasts a single arc-power value to every gear belonging to that DALI group, using H:520 GROUP LEVEL (TapHome 0–100 % is multiplied by 0xFE → DALI arc power 0–254). DALI does not let the gateway read back a group level — the bus only carries the broadcast write — so TapHome holds the last written value as the “current” level. There are no init or read scripts on group devices.
Each Group N device exposes two service actions for bulk membership management:
Add All Lamps to Group — broadcasts ADD TO GROUP (0x60+grp) via H:532 ALL COMMAND + REPEAT. Every gear on the bus joins the group regardless of its current short address.
Remove All Lamps from Group — broadcasts REMOVE FROM GROUP (0x70+grp). Every gear leaves the group.
Use group dimming for “kitchen lights”, “living-room downlights” or any zone where multiple gears should track a single dimmer. Group writes are far more efficient than driving individual gears in parallel — one Modbus transaction reaches up to 64 gears simultaneously.
Module-level diagnostics
The module exposes a single service attribute:
Slave ID — reads the Modbus Unit ID stored in FLASH register H:65221. Active only when DIP4 = OFF; with DIP4 = ON the gateway forces address 255 regardless of the FLASH value. Use this to verify the gateway address before adding more devices, especially after a commissioning round that wrote a non-default ID.
Confirm DALI bus voltage at the gear: 11.5–22.5 V (typical 14–16 V). Lower readings usually indicate a short circuit or a bus that is too long for the cable cross-section (see DALI bus topology).
Check the ERR LED on the RESI-DALI-PS — if lit, the bus is shorted, overloaded or the PSU itself is faulty.
Re-run Gear N probing in the sibling Resi Dali - Configuration template — the runtime template only retries after a random pause of up to 60 s, the commissioning template gives an immediate pass/fail per address.
Verify the gear actually has a short address. If it was replaced or factory-reset on the bus, it will be un-addressed and must be re-commissioned via Resi Dali - Configuration.
Group dimming has no effect
Confirm at least one gear is a member of the group — open Gear N → Groups on each suspected member and check that the group ID appears in the comma-separated list.
If membership is missing, fire the Add to Group action on each gear individually, or use Add All Lamps to Group on the group device for a bus-wide broadcast.
Remember that Group N is write-only — the dimmer slider in TapHome stores the last written value, but does not reflect the actual bus state. If gears are powered off, the group level command silently has no effect on them.
Lamp failure / power failure not reported
Open the gear’s DALI Status attribute. If it ends with not raised: … reported since start, the failure was already present in the gear’s first answer and is treated as its permanent state — it is shown but not raised until the bit clears once.
Power failure is not raised as an error at all; the status bit is shown in DALI Status as power cycle.
A new failure appears only after the status is polled (at least once every 60 read cycles) and read twice the same, so a short flicker of the failure bit is not reported.
Sporadic Modbus errors after commissioning
Make sure no other Modbus master (MODBUSConfigurator, PLC, BMS) is polling the gateway concurrently. DALI and Modbus do not arbitrate between masters. The Bus statistics attribute on each gear counts stale answers read away, missing answers, collisions and rejected levels since start — counts that keep rising point to concurrent traffic on the gateway or the DALI bus.
Verify RS485 GND is connected between the gateway and the TapHome power supply common — missing GND is the most common RS-485 fault on long lines.
For RTU-over-TCP through a serial bridge, confirm the bridge runs in framed RTU mode (not raw TCP socket) and that the inter-character gap on the serial side respects 9600 baud 8N1 timing.
If the symptoms appeared after changing the Slave ID with the Resi Dali - Configuration template, re-import this runtime template with the new SlaveId import parameter — the previously imported module is still polling at the old address.
Available devices 80
These devices appear in TapHome after import.
Resi DALIModule
Service Attributes
Slave ID
Reads the Modbus Unit ID stored in FLASH register H:65221 — active only when DIP4=OFF (factory default 255). Use to verify the gateway address before adding more devices.
Resi Dali
Service Attributes
${xml_slave_id}
modbusr(H,65221,uint16)
Gear 0DimmerRead and write
DALI control gear at short address 0 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 0
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 1 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 1
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 2 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 2
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 3 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 3
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 4 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 4
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 5 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 5
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 6 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 6
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 7 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 7
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 8 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 8
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 9 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 9
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 10 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 10
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 11 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 11
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 12 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 12
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 13 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 13
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 14 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 14
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 15 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 15
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 16 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 16
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 17 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 17
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 18 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 18
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 19 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 19
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 20 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 20
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 21 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 21
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 22 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 22
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 23 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 23
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 24 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 24
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 25 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 25
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 26 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 26
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 27 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 27
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 28 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 28
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 29 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 29
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 30 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 30
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 31 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 31
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 32 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 32
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 33 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 33
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 34 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 34
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 35 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 35
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 36 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 36
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 37 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 37
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 38 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 38
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 39 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 39
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 40 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 40
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 41 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 41
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 42 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 42
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 43 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 43
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 44 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 44
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 45 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 45
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 46 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 46
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 47 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 47
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 48 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 48
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 49 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 49
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 50 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 50
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 51 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 51
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 52 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 52
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 53 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 53
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 54 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 54
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 55 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 55
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 56 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 56
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 57 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 57
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 58 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 58
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 59 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 59
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 60 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 60
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 61 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 61
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 62 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 62
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI control gear at short address 63 — TapHome dimmer mapped to DALI arc power 0–100 % via H:510 LAMP LEVEL (write) and QUERY ACTUAL LEVEL via H:511 (read), bounded by the gear's own MIN / MAX LEVEL.
Register: H:511 → H:510UInt16Unit: %numeric
Service Attributes
Short Address
DALI short address (0–63) targeted by this device — fixed at template-import time and used in the upper byte of every Modbus write.
Device Type
DALI device-type byte returned by QUERY DEVICE TYPE (0x99) — reports DT0 (fluorescent), DT6 (LED driver), DT8 (colour / tunable white) etc., or -- when no answer.
Physical Min Level
Hardware-imposed minimum dimming level reported by the gear — read from QUERY PHYSICAL MIN LEVEL (0x9A), as a percentage.
Max Level
Configured DALI MAX LEVEL — read from QUERY MAX LEVEL (0xA1); used as the upper bound when scaling TapHome 0–100 % to DALI arc power.
Min Level
Configured DALI MIN LEVEL — read from QUERY MIN LEVEL (0xA2); used as the lower bound when scaling TapHome 0–100 % to DALI arc power.
Power Up Level
Brightness restored after DALI bus power is recovered — read from QUERY POWER ON LEVEL (0xA3).
System Failure Level
Brightness adopted when the DALI bus loses communication for more than 500 ms — read from QUERY SYSTEM FAILURE LEVEL (0xA4).
Groups
Comma-separated list of DALI groups (0–15) the gear belongs to — decoded from QUERY GROUPS 0-7 (0xC0) and QUERY GROUPS 8-15 (0xC1); shows None or e.g. 0,3,7.
Support Lamp Failure
Whether the lamp / driver supports lamp-failure detection — Yes / No / --. Gates the Lamp failure! error in the periodic readscript.
Support Power Failure
Whether the lamp / driver supports power-failure detection — Yes / No / --. Gates the Power failure! error in the periodic readscript.
DALI Version
Bus statistics
Service Actions
Add to Group
Adds this gear to a DALI group (0–15) via ADD TO GROUP (0x60+grp) — auto-repeated within 100 ms as required for DALI configuration commands.
Remove from Group
Removes this gear from a DALI group (0–15) via REMOVE FROM GROUP (0x70+grp).
Reset to Default Settings
Sends DALI RESET (0x20) — restores every NVM parameter of the gear (max / min / power-on / system-failure level, group membership, scenes) to the manufacturer default.
Set Startup Levels
Captures the current arc power and stores it as Power On Level and System Failure Level — sequence STORE ACTUAL LEVEL IN DTR (0x21) → STORE DTR AS POWER ON LEVEL (0x2C) → STORE DTR AS SYSTEM FAILURE LEVEL (0x2D).
Disable fading
Gear 63
Read (module)
var x := 0; var rx := 0; var y := 0;
if Status > 0
Status := Status - 1;
adderror(3, "Gear not responding!");
return(0);
end
# checkStatus: ReadLevel resets it while the gear answers; statusPoll: QUERY STATUS at least once per 60 runs
checkStatus := checkStatus - 1;
statusPoll := statusPoll - 1;
if checkStatus < 1 or statusPoll < 1
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
# a single lost answer happens on DALI: ask once more before declaring the gear missing
if x = 0x8000
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
end
if x <= 0xFF
# a changed failure bit must be read twice the same before it is taken
if statusSeen = 1 and getbits(x, 0, 2) != getbits(gearStatus, 0, 2)
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
x := gearStatus;
end
end
if statusSeen = 0
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
end
# a bit that clears ends its ignore, so a later failure is raised
if (getbit(x, 0) = 0, ignGear := 0);
if (getbit(x, 1) = 0, ignLamp := 0);
gearStatus := x;
checkStatus := 60;
statusPoll := 60;
else
if x = 0x8000
Status := RANDINT(10, 60);
adderror(3, "Gear not responding!");
return(0);
end
end
end
# messages last one run only, so they are raised from the stored status on every run
if ((getbit(gearStatus, 0) = 1) and (ignGear = 0), adderror(1, "Control gear failure!"));
if ((getbit(gearStatus, 1) = 1) and (ignLamp = 0), adderror(2, "Lamp failure!"));
Initialize
var x := 0; var rx := 0;
# QUERY STATUS 0x90: every reply byte proves the gear is present; 0x8000 = no answer, 0x20FF = bus collision
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
statusSeen := 0;
if x <= 0xFF
# failure bits a gear reports from its first answer are its permanent state, not an event: shown, not raised
gearStatus := x;
ignGear := getbit(x, 0);
ignLamp := getbit(x, 1);
statusSeen := 1;
Status := 0;
else
Status := RANDINT(1, 60);
end
if Status = 0
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, maxLevel := x);
end
Read level
var x := 0; var rx := 0; var y := 0;
if Status = 0
if minLevel = 0
# an unread answer left in the gateway would be taken for this query: read it away and count it
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x <= 0xFE, minLevel := x);
end
x := modbusr(SH, 511, uint16); if (x != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (x = 0x8000, cntNone := cntNone + 1); if (x = 0x20FF, cntColl := cntColl + 1);
if (x != 0x8000 or rx, checkStatus := 60);
# 0xFF = MASK, 0x20FF = collision, 0x8000 = no answer: keep the last level instead of a phantom value
if x > 0xFE
return(Le);
end
# an actual level is 0 or between the gear's min and max: anything else is not this gear's answer
if x > 0 and x < minLevel
cntBad := cntBad + 1;
return(Le);
end
# a changed level must be read twice the same before it is taken
if x != lastRaw
y := modbusr(SH, 511, uint16); if (y != 0x8000, cntStale := cntStale + 1);
modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
cntQ := cntQ + 1; if (y = 0x8000, cntNone := cntNone + 1); if (y = 0x20FF, cntColl := cntColl + 1);
if y != x
cntBad := cntBad + 1;
return(Le);
end
lastRaw := x;
end
return(if(x = 0, 0, linear(x, minLevel, 0.01, maxLevel, 1)));
else
return(NaN);
end
var x := 0; var y := 0; var rx := 0; var s := ""; var i := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x99);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
x := modbusr(SH, 511, uint16);
if (x < 0xFF, return("DT" + x));
if x = 0xFF
while i < 8
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA7);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
y := modbusr(SH, 511, uint16);
if y < 0xFE
s := if(s = "", "DT" + y, s + ", DT" + y);
i := i + 1;
else
i := 8;
end
loop
return(if(s = "", "MASK", s));
end
end
return("--")
Physical Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x9A);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Max Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA1);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Min Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA2);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
Power Up Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA3);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
System Failure Level
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA4);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if (x <= 0xFE, return(round((x / 0xFE) * 100) + " %"));
end
return("--")
${xml_groups}
var x := 0; var rx := 0;
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC0);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g1 := modbusr(SH, 511, uint16);
if (g1 > 0xFF, return("--"));
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xC1);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var g2 := modbusr(SH, 511, uint16);
if (g2 > 0xFF, return("--"));
var ret := "";
if (getbit(g1, 0), ret := ret + "0");
if (getbit(g1, 1), if (ret = "", ret := "1", ret := ret + ",1"));
if (getbit(g1, 2), if (ret = "", ret := "2", ret := ret + ",2"));
if (getbit(g1, 3), if (ret = "", ret := "3", ret := ret + ",3"));
if (getbit(g1, 4), if (ret = "", ret := "4", ret := ret + ",4"));
if (getbit(g1, 5), if (ret = "", ret := "5", ret := ret + ",5"));
if (getbit(g1, 6), if (ret = "", ret := "6", ret := ret + ",6"));
if (getbit(g1, 7), if (ret = "", ret := "7", ret := ret + ",7"));
if (getbit(g2, 0), if (ret = "", ret := "8", ret := ret + ",8"));
if (getbit(g2, 1), if (ret = "", ret := "9", ret := ret + ",9"));
if (getbit(g2, 2), if (ret = "", ret := "10", ret := ret + ",10"));
if (getbit(g2, 3), if (ret = "", ret := "11", ret := ret + ",11"));
if (getbit(g2, 4), if (ret = "", ret := "12", ret := ret + ",12"));
if (getbit(g2, 5), if (ret = "", ret := "13", ret := ret + ",13"));
if (getbit(g2, 6), if (ret = "", ret := "14", ret := ret + ",14"));
if (getbit(g2, 7), if (ret = "", ret := "15", ret := ret + ",15"));
if (ret = "", return("None"), return(ret));
else
return("--");
end
DALI Status
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x90);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var s := "";
if (getbit(x, 0), s := if(s = "", "gear failure", s + ", gear failure"));
if (getbit(x, 1), s := if(s = "", "lamp failure", s + ", lamp failure"));
if (getbit(x, 2), s := if(s = "", "lamp on", s + ", lamp on"));
if (getbit(x, 3), s := if(s = "", "limit error", s + ", limit error"));
if (getbit(x, 4), s := if(s = "", "fade running", s + ", fade running"));
if (getbit(x, 5), s := if(s = "", "reset state", s + ", reset state"));
if (getbit(x, 6), s := if(s = "", "missing short address", s + ", missing short address"));
if (getbit(x, 7), s := if(s = "", "power cycle", s + ", power cycle"));
var ign := if((ignGear = 1) and (ignLamp = 1), "gear and lamp failure", if(ignGear = 1, "gear failure", if(ignLamp = 1, "lamp failure", "")));
return(if(s = "", "OK", s) + " (0x" + tostring(x, "X2") + ")" + if(ign = "", "", "; not raised: " + ign + " reported since start"));
end
end
return("--")
Fade
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA5);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
var t := getbits(x, 4, 4);
var ret := if(t = 0, "off", t + " (" + round(sqrt(power(2, t)) * 5) / 10 + " s)");
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0xA8);
sleep(5); rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var e := modbusr(SH, 511, uint16);
if (t = 0 and e <= 0xFF and e != 0, ret := "extended 0x" + tostring(e, "X2"));
return("fade time " + ret + ", fade rate " + getbits(x, 0, 4));
end
end
return("--")
DALI Version
if Status = 0
modbusr(SH, 511, uint16); modbusw(SH, 511, uint16, (ShortAddress << 8) + 0x97);
sleep(5); var rx := getbits(modbusr(SH, 550, uint16), 0, 2); if(rx, 0, sleep(50));
var x := modbusr(SH, 511, uint16);
if x <= 0xFF
return(if(x >= 8, "DALI-2 " + getbits(x, 2, 6) + "." + getbits(x, 0, 2), "DALI-1") + " (" + x + ")");
end
end
return("--")
DALI broadcast group 0 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 0;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 0;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 1DimmerRead and write
DALI broadcast group 1 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 1;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 1;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 2DimmerRead and write
DALI broadcast group 2 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 2;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 2;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 3DimmerRead and write
DALI broadcast group 3 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 3;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 3;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 4DimmerRead and write
DALI broadcast group 4 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 4;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 4;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 5DimmerRead and write
DALI broadcast group 5 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 5;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 5;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 6DimmerRead and write
DALI broadcast group 6 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 6;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 6;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 7DimmerRead and write
DALI broadcast group 7 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 7;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 7;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 8DimmerRead and write
DALI broadcast group 8 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 8;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 8;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 9DimmerRead and write
DALI broadcast group 9 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 9;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 9;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 10DimmerRead and write
DALI broadcast group 10 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 10;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 10;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 11DimmerRead and write
DALI broadcast group 11 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 11;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 11;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 12DimmerRead and write
DALI broadcast group 12 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 12;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 12;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 13DimmerRead and write
DALI broadcast group 13 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 13;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 13;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 14DimmerRead and write
DALI broadcast group 14 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
var GroupAddress := 14;
modbusw(SH, 532, uint16, 0x60 + GroupAddress)
${xml_remove_from_group_all_lamps}
var GroupAddress := 14;
modbusw(SH, 532, uint16, 0x70 + GroupAddress)
Group 15DimmerRead and write
DALI broadcast group 15 (0–15) — write-only TapHome dimmer that broadcasts a single arc-power value to every gear in this group via H:520 GROUP LEVEL. The bus does not echo group levels, so TapHome holds the last written value.
UInt16Unit: %numeric
Service Actions
Add All Lamps to Group
Broadcasts ADD TO GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus joins this group regardless of its current short address.
Remove All Lamps from Group
Broadcasts REMOVE FROM GROUP via H:532 ALL COMMAND + REPEAT — every gear on the bus leaves this group.
H:531ALL COMMAND (broadcast DALI command) — Single-shot broadcast DALI command (no repeat). Template uses H:532 (ALL COMMAND + REPEAT) for group membership but never exposes plain ALL OFF / ALL ON / ALL ARC POWER as a service action — turn-on/off-all are not present (sibling daliconfig template has them via H:530)
H:530ALL LEVEL (broadcast arc power) — Sets brightness for every gear in one Modbus write. Convenient 'turn off all lamps' / 'turn on all lamps' shortcut — implemented in the sibling daliconfig template, missing in this operational template
H:521GROUP COMMAND (per-group DALI command) — Per-group DALI command (single-shot). Could expose group-level OFF / RECALL MIN / RECALL MAX / GO TO SCENE as service actions on each Group device, but template only writes H:520 GROUP LEVEL
H:522GROUP COMMAND + REPEAT — Per-group DALI configuration command (auto-repeated within 100 ms). Required for STORE DTR AS GROUP SCENE etc. — not exposed as a service action
H:541DIRECT 16-BIT FRAME — Raw DALI 1.0 frame send. Used by sibling daliconfig template for the DALI 2.0 random-addressing algorithm; not needed for runtime brightness control
I:10020-I:10027DALI 24-BIT FRAME — DALI 2.0 24-bit frames — required for DT8 colour control (XY, colour temperature, RGBW), DALI 2.0 control gear queries, and DALI-2 input devices (push-buttons, presence detectors). Template exposes only DALI 1.0 brightness layer per gear
I:10030-I:10047DALI 25-BIT eDALI FRAME — Lunatone-proprietary 25-bit eDALI frames (auto and user redundant-bit variants). Not used by any DALI 1.0 gear
I:10050-I:10067DALI 28-BIT / 32-BIT FRAME — Extended DALI 2.0 frames (memory bank access, DALI-2 application controllers). Template scope is single-channel arc power per gear
H:500 (DSI VALUE)DSI 8-bit value send — Send a raw 8-bit DSI/DALI value with no addressing (bus-level diagnostics). Bypassed by every TapHome script
C:0 / H:551DALI Bus Error — 1 = DALI bus fault / short circuit / missing PSU. Useful diagnostic — could be added as a module-level service attribute. Currently bus errors only surface indirectly through 'Gear not responding!' errors emitted by per-gear readscripts
H:100DALI PRIORITY SLOT — 0..4 → 12-16 ms forward-frame timing. Default 2 (configuration). Bus-tuning parameter; template runs at default
H:6000DIP SWITCH / SOFTWARE RESET — Read returns the 4 DIP switch values; write 1 reboots the gateway. Sibling daliconfig template exposes Reset Gateway / Set Slave ID; this runtime template intentionally does not (commissioning concern)
H:65222 / H:65224 / H:65225BAUD_RATE / PARITY / STOP_BITS (FLASH) — FLASH-stored serial parameters. Template hard-codes 9600 8N1 in connection_details, so these are out of scope
I:0 / I:50-I:53 / scenesDALI 1.0 scenes (recall / store / query) — DALI 1.0 standard supports 16 stored scenes per gear/group recallable via GO TO SCENE (0x10..0x1F) and storable via STORE DTR AS SCENE (0x40..0x4F). Template exposes per-gear ADD/REMOVE FROM GROUP and RESET, but no scene recall/store/remove/query actions
H:512 (RECALL MAX/MIN/GOTO LAST/UP/DOWN/STEP)DALI 1.0 high-level commands per gear — RECALL MAX LEVEL (0x05), RECALL MIN LEVEL (0x06), UP (0x01), DOWN (0x02), STEP UP (0x03), STEP DOWN (0x04), GO TO LAST ACTIVE LEVEL (0x0A) — useful as service actions for visual feedback / smooth dimming. Not exposed; brightness goes only through linear scaling
H:512 (STORE DTR AS MAX/MIN/POWER ON/SYSTEM FAILURE LEVEL)Per-gear configuration write commands — STORE DTR AS MAX LEVEL (0x2A), STORE DTR AS MIN LEVEL (0x2B), STORE DTR AS POWER ON LEVEL (0x2C), STORE DTR AS SYSTEM FAILURE LEVEL (0x2D), STORE DTR AS FADE TIME / FADE RATE — template has 'Set Startup Levels' (combines 0x21, 0x2C, 0x2D) but does NOT expose individual writes for max/min/fade-time/fade-rate
H:511 (QUERY FADE TIME / FADE RATE / RANDOM ADDRESS / EXT VERSION)Additional DALI queries — QUERY FADE TIME / FADE RATE (0xA5), QUERY VERSION NUMBER (0x97), QUERY RANDOM ADDRESS H/M/L (0x98/0xC2/0xC3), QUERY CONTENT DTR/DTR1/DTR2 — not exposed in service attributes, only the 10 attributes listed per gear are populated
H:511 (QUERY CONTROL GEAR / RESET STATE / LIMIT ERROR / LAMP POWER ON / MISSING SHORT ADDRESS)DALI gear health / topology queries — QUERY CONTROL GEAR (0x90), QUERY RESET STATE (0x95), QUERY LIMIT ERROR (0x94), QUERY LAMP POWER ON (0x93), QUERY MISSING SHORT ADDRESS (0x96, broadcast) — diagnostic queries. Could be useful as module-level diagnostics; template exposes only QUERY STATUS / LAMP FAILURE / POWER FAILURE / DEVICE TYPE / MIN-MAX-PHYSICAL MIN-POWER UP-SYSTEM FAILURE LEVEL / GROUPS
H:511 (READ MEMORY LOCATION 0xC5)DALI memory bank read — READ MEMORY LOCATION (0xC5) is required to read DALI 2.0 memory banks (Bank 0 device GTIN, FW version, serial number; Bank 1 for emergency lighting). Not used
ASCII protocol commandsParallel ASCII text protocol — RESI gateway also exposes a CR-terminated text protocol (#LARC, #GARC, #AARC, #LGS, #LCMD, #LCMDA, #DALI CMDxx etc.). Template uses Modbus exclusively — ASCII would only matter for diagnostics/terminal access
DT6 fade time / fade rate / DAPC sequenceSmooth dimming primitives — DAPC (Direct Arc Power Control) sequence allows fast continuous level updates for smooth dimming. Each gear has stored fade time / fade rate that affect transitions. Template writes raw arc power without configuring fade behaviour
DT8 colour control (XY, colour temperature, RGBW)DALI DT8 tunable white / RGB / RGBW — DT8 colour control gears (tunable white CCT, XY colour, RGBW) require DALI 2.0 24-bit frames sent via H:541 / I:10020. Template exposes plain ModbusDimmer per gear — for DT8 lamps use a dedicated DT8 template
DT1 emergency lightingDALI DT1 self-contained emergency lights — Emergency-luminaire device type with periodic self-tests (function/duration test) and battery state queries. Out of scope — template is general-purpose dimming
The WhatsApp message was not sent within 60 minutes.
✓
The request is with support
Beta · TapHome 2026.1
We're looking for testers of the new version
You are among the first partners who can roll out 2026.1 to customers. The support assistant does the upgrade for you on WhatsApp or by e-mail — it checks the unit and makes a backup before the change.
Try 2026.1 before everyone else. The support assistant does the upgrade for you on WhatsApp or by e-mail — it checks the unit and makes a backup before the change.