Skip to content

Cyclic Write (CW) does not work without Poll enabled — registers silently excluded #771

@mtibke

Description

@mtibke

Environment

  • Adapter version: 8.0.3
  • Node.js: v22.22.2
  • js-controller: 7.0.7

Description

Cyclic Write (CW) on Holding Registers does not work when the "Poll" checkbox is disabled for the register. The CW write never fires, even though cw: true is set in the config. No error or warning is logged — the register is silently excluded.

Root Cause (Source Code Analysis)

Bug 1: Config filter excludes non-polled registers

In src/main.ts (index.ts compiled), the holdingRegs config is filtered before iterateAddresses() processes CW flags:

// ~line 1218
device.holdingRegs.config = (this.config.holdingRegs as Modbus.RegisterInternal[]).filter(
    e => e.poll && e.deviceId === deviceId,
);

Registers without poll: true are excluded from the config array entirely. When iterateAddresses() later processes the config to populate the cyclicWrite array, the CW register is simply not there.

Bug 2: ackObjects dependency prevents write even if filter is bypassed

In src/lib/Master.ts, the CW write method reads from ackObjects:

// ~line 643
if (this.ackObjects[id]) {
    await this.#writeValue(id, this.ackObjects[id].val);
}

ackObjects is only populated during the READ (poll) phase. If a register is never polled, ackObjects[id] is undefined, and the write is silently skipped.

Expected Behavior

A register with cw: true and poll: false should still be written cyclically. The adapter should:

  1. Not filter out CW registers from the config just because poll is disabled
  2. For CW-only registers (no poll), use the last setState value (from ioBroker state DB) instead of requiring a polled ackObjects entry

Steps to Reproduce

  1. Add a Holding Register with CW enabled and Poll disabled
  2. Set the ioBroker state value to any number (e.g., 1) with ack: true
  3. Enable debug logging
  4. Observe: no write appears in the debug log for that register

Use Case

This is critical for devices that require a periodic heartbeat write (e.g., Vestel EVC04 EV charger, which expects a write to register 6000 every few seconds to keep the TCP connection alive). CW would be the perfect built-in mechanism for this, but currently requires a workaround script.

Workaround

Use an ioBroker JavaScript script to periodically write the value:

setInterval(() => {
    setState('modbus.0.holdingRegisters.46001_Heartbeat', 1, false);
}, 5000);

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions