Resolving NullReferenceException in Rapid SCADA KpMQTT Driver
The Rapid SCADA KpMQTT driver is a community-maintained communication module that bridges MQTT brokers into the Rapid SCADA 5/6 channel model. Field deployments frequently surface a single, recurring .NET runtime fault during the first poll cycle:
The exception is thrown inside the Communicator service before any input channel number (Cnl) is mapped to a tag, which means the failure is almost always in the device template (DevTemplate) or in the supporting driver assemblies, not in the topic payload itself. This reference document walks through root cause analysis, file-level remediation, and verification procedures using the official Rapid SCADA 6 source tree as the canonical implementation reference.
1. Affected Versions and Components
| Component | Affected Versions | Status |
|---|---|---|
| KpMQTT driver DLL | Pre-release builds on bersim/OpenKPs KpMQTT | Community supported |
| Rapid SCADA Server | 5.x and 6.x branch | See RapidScada/scada-v6 |
| Communicator service | ScadaComm.exe / ScadaCommunicator | Runs under ServerUser account |
| Configuration database | BaseDAT.xml, DevTemplate.xml | XML, UTF-8 encoded |
The KpMQTT driver is distributed as a set of compiled .NET DLLs that must be unblocked on Windows before the .NET runtime will JIT-load them. A blocked assembly silently loads into the AppDomain and then throws NullReferenceException on the first property access, which is the most common cause reported by integrators deploying the driver for the first time.
2. Root Cause Analysis
The exception is generated by the Common Language Runtime when an object dereference is performed on a null reference. In the KpMQTT driver, the following four conditions have been observed in production deployments:
-
Blocked driver DLLs downloaded from GitHub. Windows marks files with the
Zone.Identifieralternate data stream as "from the internet"; the .NET loader initializes the type but skips IL verification, then fails on the first member access. -
Missing or malformed
<MqttParams>section. EmptyUserName/Passwordtags combined with a definedPortcause the MqttClient constructor branch to dereference an uninitialized credential object. -
Empty
<MqttSubTopics>collection. The driver subscribes duringInit(); if no<Topic>nodes exist, the internal subscription list is null and the next poll cycle raises the exception. -
Unresolved
NumCnl. TheNumCnlvalue (e.g.,1020) must already exist inBaseDAT.xml. A channel number not registered in the device's input channel table causes the tag-binding routine to dereference a null tag descriptor.
3. Required XML Schema
A valid DevTemplate for the KpMQTT driver follows the schema below. Each section is mandatory; an empty tag must still be present.
<?xml version="1.0" encoding="UTF-8"?>
<DevTemplate>
<MqttParams Password="" UserName="" Port="1883" ClientID="KpMQTTrs111" Hostname="192.168.1.106"/>
<RapSrvCnf ServerPwd="12345" ServerUser="ScadaComm" ServerPort="10000" ServerHost="127.0.0.1"/>
<MqttSubTopics>
<Topic NumCnl="1020" QosLevel="0" TopicName="ha/_temperature1"/>
</MqttSubTopics>
</DevTemplate>
| Element | Attribute | Required | Description |
|---|---|---|---|
| <MqttParams> | Hostname | Yes | Broker IP or DNS name (e.g., 192.168.1.106) |
| <MqttParams> | Port | Yes | TCP listener port, default 1883 (TLS 8883) |
| <MqttParams> | ClientID | Yes | Must be unique on the broker |
| <MqttParams> | UserName | No | Leave blank for anonymous brokers |
| <MqttParams> | Password | No | Leave blank for anonymous brokers |
| <RapSrvCnf> | ServerHost | Yes | Rapid SCADA Server listening address |
| <RapSrvCnf> | ServerPort | Yes | Default 10000 |
| <RapSrvCnf> | ServerUser | Yes | Communicator service account |
| <RapSrvCnf> | ServerPwd | Yes | Communicator service password |
| <Topic> | TopicName | Yes | MQTT subscription filter |
| <Topic> | NumCnl | Yes | Input channel number to bind |
| <Topic> | QosLevel | Yes | 0, 1, or 2 per MQTT spec |
4. Prerequisites
- Rapid SCADA Server 5.x or 6.x installed and running (verify with RapidScada/scada-v6 release notes for current build).
- Administrator rights on the Windows host to unblock DLLs and modify
C:\SCADA\directory. - An MQTT broker reachable on the network (Mosquitto, EMQX, HiveMQ, or cloud-hosted).
- The KpMQTT driver package from bersim/OpenKPs.
- Text editor capable of saving UTF-8 XML without BOM (Notepad++, VS Code).
5. Step-by-Step Remediation
5.1 Unblock the Driver DLLs
- Right-click each DLL in the KpMQTT distribution folder (typically
KpMQTT.dll,M2Mqtt.dll). - Select Properties.
- On the General tab, check Unblock at the bottom.
- Click Apply and OK.
For unattended deployment, run from an elevated PowerShell prompt:
Get-ChildItem "C:\SCADA\KP\*" -Recurse -Include *.dll | Unblock-File
5.2 Validate the Device Template
- Open the device's
DevTemplateXML in the Communicator configuration table editor. - Confirm the
<MqttSubTopics>section contains at least one<Topic>node. - Confirm every
NumCnlvalue exists inBaseDAT.xmlinput channels of the same device. - Verify
Hostnameresolves viapingorTest-NetConnection -Port 1883(PowerShell).
5.3 Register the Input Channel
Each MQTT topic must be paired with a valid input channel. In the Rapid SCADA Administrator:
- Open the device's input channels table.
- Add a row with
Cnl = 1020, signal type appropriate to the payload (typically 1 = Analog or 0 = Discrete). - Set the tag formula if transformation is required (e.g., scaling
x*0.1for °C/10 raw values).
5.4 Restart the Communicator Service
net stop ScadaCommunicator
net start ScadaCommunicator
6. Verification Procedure
- Open the Rapid SCADA Communicator log at
C:\SCADA\ScadaComm\Log\. Confirm noNullReferenceExceptionentries appear within 60 seconds of service start. - From the broker host, publish a test payload:
mosquitto_pub -h 192.168.1.106 -t ha/_temperature1 -m "23.5" - In Rapid SCADA Webstation, navigate to the channel 1020 view. The current value should update within the configured poll interval.
- Check the event log for
Data receivedentries tied to channel 1020.
7. Diagnostic Matrix
| Symptom | Likely Cause | Fix |
|---|---|---|
| NullReferenceException on start | Blocked DLLs | Unblock per section 5.1 |
| NullReferenceException on first poll | Empty MqttSubTopics | Add at least one <Topic> |
| Exception mentions NumCnl value | Channel not registered | Create the channel in BaseDAT |
| Connection refused in log | Wrong port or firewall | Verify Port=1883, open firewall |
| Auth failed | Wrong UserName/Password | Populate credentials in XML |
| Spanish-language exception text | Localized OS .NET runtime | Fault is identical; fix root cause |
8. Network and Security Considerations
Port 1883 is the unencrypted MQTT default. For production deployments, use TLS on 8883 and provide CA certificate paths in the <MqttParams> extension attributes supported by M2Mqtt. Ensure Windows Firewall inbound rules allow the Communicator host to reach the broker port. If the broker is on a different VLAN, verify routing and that the ServerUser account has local policy rights to create outbound TCP sockets.
9. Migrating to Rapid SCADA 6
The RapidScada/scada-v6 repository is the modern .NET 6+ rewrite. Drivers built against the v5 KP API are not directly compatible; the KpMQTT driver requires a v6-compatible recompile using the new IDriver interface declared in Scada.Comm.Drivers. Channel binding is now performed through the CnlTagFactory rather than NumCnl attribute lookup. Plan migration by:
- Exporting the v5 DevTemplate to JSON.
- Recompiling KpMQTT against the v6 SDK.
- Remapping topic-to-channel bindings via the new Configuration application.
10. Best Practices
- Always unblock DLLs immediately after extracting the GitHub ZIP.
- Keep
ClientIDunique per device instance to avoid broker kicks. - Set
QosLevel = 1for sensor data requiring at-least-once delivery. - Restrict
ServerUserprivileges; theScadaCommaccount only needs write access to the channel database. - Use a wildcard topic filter (e.g.,
ha/+/temperature) only when the downstream channel mapping is verified.
FAQ
What causes "Object reference not set to an instance of an object" in KpMQTT?
The exception is a .NET NullReferenceException raised when the driver dereferences an uninitialized object, most commonly because the KpMQTT DLLs were downloaded with the Windows "blocked" flag, the MqttSubTopics section is empty, or the referenced NumCnl does not exist in BaseDAT.xml.
How do I unblock KpMQTT DLLs on Windows?
Right-click each DLL, choose Properties, check "Unblock" on the General tab, and apply. From PowerShell run Get-ChildItem "C:\SCADA\KP\*" -Recurse -Include *.dll | Unblock-File.
Where is the KpMQTT DevTemplate file located?
It is stored inside the Communicator configuration database for each device, typically under C:\SCADA\BaseDAT\. The XML must include <MqttParams>, <RapSrvCnf>, and at least one <Topic> inside <MqttSubTopics>.
Is KpMQTT compatible with Rapid SCADA 6?
Not directly. The v5 KP API uses NumCnl bindings that were replaced in v6 by CnlTagFactory. Recompile KpMQTT against the v6 SDK from the RapidScada/scada-v6 repository.
How do I verify the MQTT driver is working after a fix?
Publish a test payload with mosquitto_pub to the configured topic, then view channel 1020 in Rapid SCADA Webstation. The Communicator log should show "Data received" without NullReferenceException entries within 60 seconds of service start.