Summary
ControlByWeb WebRelay Wireless modules expose a built-in web server responding to HTTP GET requests for state monitoring and I/O control, and additionally support Modbus/TCP, SNMP (V1/V2c/V3), MQTT/Sparkplug B, Remote Services (device-initiated TCP V1), and the ControlByWeb Cloud DAT URL API. This spec covers the HTTP GET request interface documented for custom TCP/IP integrations (relay control, pulse commands, register/counter/on-time setters, state read endpoints), the Modbus/TCP function codes and PLC addressing examples, SNMP PDUs and standard objects, MQTT subscribe/publish operations, and Remote Services connection mechanics.
Transport
protocols:
- tcp
- udp # inferred: SNMP conventionally uses UDP; source documents SNMP V1/V2c/V3 without specifying transport layer
addressing:
port: 80 # HTTP default; source references "not port 80" alternative (e.g. :8000). Modbus/TCP uses port 502 (explicitly stated line 293, configurable under Advanced Network tab). SNMP/MQTT ports not stated in source.
auth:
type: basic # source documents Base64 Authorization header when User account enabled (default name:password none:webrelay); default no-auth path also documented. Modbus/TCP requires User account disabled (no password mechanism).
Traits
- queryable # inferred from state.xml/state.json read endpoints and SNMP GetRequest
- routable # inferred from relay on/off/pulse commands
- levelable # inferred from register/analog settable values
Actions
# === HTTP GET - state read ===
- id: read_state_xml
label: Read state.xml
kind: query
command: "GET /state.xml HTTP/1.1\r\n\r\n"
params: []
- id: read_state_json
label: Read state.json
kind: query
command: "GET /state.json HTTP/1.1\r\n\r\n"
params: []
- id: read_custom_state_xml
label: Read customState.xml
kind: query
command: "GET /customState.xml HTTP/1.1\r\n\r\n"
params: []
- id: read_custom_state_json
label: Read customState.json
kind: query
command: "GET /customState.json HTTP/1.1\r\n\r\n"
params: []
- id: read_state_xml_with_units
label: Read state.xml with units
kind: query
command: "GET /state.xml?showUnits=1 HTTP/1.1\r\n\r\n"
params: []
# showUnits=1 appends units to sensor values (e.g. oneWireSensorX returns "77.3 F")
- id: read_state_json_with_units
label: Read state.json with units
kind: query
command: "GET /state.json?showUnits=1 HTTP/1.1\r\n\r\n"
params: []
# === HTTP GET - relay control ===
- id: relay1_off
label: Turn Relay 1 OFF
kind: action
command: "GET /state.xml?relay1=0 HTTP/1.1\r\n\r\n"
params: []
- id: relay1_on
label: Turn Relay 1 ON
kind: action
command: "GET /state.xml?relay1=1 HTTP/1.1\r\n\r\n"
params: []
- id: relay1_pulse
label: Pulse Relay 1 (default duration)
kind: action
command: "GET /state.xml?relay1=2 HTTP/1.1\r\n\r\n"
params: []
- id: relay2_off
label: Turn Relay 2 OFF
kind: action
command: "GET /state.xml?relay2=0 HTTP/1.1\r\n\r\n"
params: []
- id: relay2_on
label: Turn Relay 2 ON
kind: action
command: "GET /state.xml?relay2=1 HTTP/1.1\r\n\r\n"
params: []
- id: relay2_pulse
label: Pulse Relay 2 (default duration)
kind: action
command: "GET /state.xml?relay2=2 HTTP/1.1\r\n\r\n"
params: []
# === HTTP GET - pulse with duration ===
- id: relay1_pulse_5s
label: Pulse Relay 1 for 5 seconds
kind: action
command: "GET /state.json?pulseTime1=5&relay1=2 HTTP/1.1\r\n\r\n"
params: []
- id: relay1_pulse_15s
label: Pulse Relay 1 for 15 seconds
kind: action
command: "GET /state.json?pulseTime1=15&relay1=2 HTTP/1.1\r\n\r\n"
params: []
- id: relay1_pulse_custom
label: Pulse Relay 1 for custom duration
kind: action
command: "GET /state.json?pulseTime1={seconds}&relay1=2 HTTP/1.1\r\n\r\n"
params:
- name: seconds
type: integer
description: Pulse duration in seconds (must precede relay1=2 in query string)
# === HTTP GET - on-time / counter / register setters ===
- id: reset_onTime1
label: Reset onTime1
kind: action
command: "GET /state.xml?onTime1={value} HTTP/1.1\r\n\r\n"
params:
- name: value
type: integer
description: Seconds to set (e.g. 0 to reset, 5 to set 5)
- id: reset_totalOnTime1
label: Reset totalOnTime1
kind: action
command: "GET /state.xml?totalOnTime1={value} HTTP/1.1\r\n\r\n"
params:
- name: value
type: integer
description: Seconds to set (e.g. 0 to reset, 5 to set 5)
- id: set_counter1
label: Set counter1
kind: action
command: "GET /state.json?count1={value} HTTP/1.1\r\n\r\n"
params:
- name: value
type: integer
description: Counter value (e.g. 200)
- id: set_register1
label: Set register1
kind: action
command: "GET /state.xml?register1={value} HTTP/1.1\r\n\r\n"
params:
- name: value
type: number
description: Numeric value (e.g. 10.5)
- id: set_custom_register
label: Set custom-named register via customState
kind: action
command: "GET /customState.xml?myRegister1={value} HTTP/1.1\r\n\r\n"
params:
- name: value
type: number
description: Numeric value; tag name (e.g. myRegister1) is the user-configured name
# === HTTP GET - multi-command ===
- id: multi_command_state
label: Send multiple commands (state)
kind: action
command: "GET /state.json?relay1={r1}&relay2={r2} HTTP/1.1\r\n\r\n"
params:
- name: r1
type: integer
description: Relay 1 value (0=off, 1=on, 2=pulse)
- name: r2
type: integer
description: Relay 2 value (0=off, 1=on, 2=pulse)
- id: multi_command_custom_state
label: Send multiple commands (customState)
kind: action
command: "GET /customState.xml?relay1={r1}&relay2={r2} HTTP/1.1\r\n\r\n"
params:
- name: r1
type: integer
description: Relay 1 value (0=off, 1=on, 2=pulse)
- name: r2
type: integer
description: Relay 2 value (0=off, 1=on, 2=pulse)
# === HTTP GET - log files ===
- id: read_log_txt
label: Read log.txt
kind: query
command: "GET /log.txt HTTP/1.1\r\n\r\n"
params: []
- id: erase_log_txt
label: Erase log.txt
kind: action
command: "GET /log.txt?erase=1 HTTP/1.1\r\n\r\n"
params: []
- id: read_syslog_txt
label: Read syslog.txt
kind: query
command: "GET /syslog.txt HTTP/1.1\r\n\r\n"
params: []
# Setup username/password required to access this file
- id: erase_syslog_txt
label: Erase syslog.txt
kind: action
command: "GET /syslog.txt?erase=1 HTTP/1.1\r\n\r\n"
params: []
# === Modbus/TCP - generic function codes (port 502) ===
- id: modbus_read_coils
label: Modbus Read Coils (FC 01)
kind: query
command: "Modbus/TCP function 0x01 on port 502 (start address and quantity per device Modbus map)"
params: []
- id: modbus_read_discrete_inputs
label: Modbus Read Discrete Inputs (FC 02)
kind: query
command: "Modbus/TCP function 0x02 on port 502 (start address and quantity per device Modbus map)"
params: []
- id: modbus_read_holding_registers
label: Modbus Read Holding Registers (FC 03)
kind: query
command: "Modbus/TCP function 0x03 on port 502 (start address and quantity per device Modbus map)"
params: []
- id: modbus_write_single_coil
label: Modbus Write Single Coil (FC 05)
kind: action
command: "Modbus/TCP function 0x05 on port 502; output value 0x00=Off, 0xFF=On (address per Modbus map)"
params: []
- id: modbus_write_multiple_coils
label: Modbus Write Multiple Coils (FC 15)
kind: action
command: "Modbus/TCP function 0x0F on port 502 (start address, quantity, byte count, 0x0000-0xFFFF payload)"
params: []
- id: modbus_write_multiple_registers
label: Modbus Write Multiple Registers (FC 16)
kind: action
command: "Modbus/TCP function 0x10 on port 502 (IEEE 754 float, register count must be even, address per Modbus map)"
params: []
# === Modbus/TCP - documented PLC addressing examples (concrete addresses) ===
- id: modbus_read_relay1
label: Modbus Read Relay 1
kind: query
command: "Modbus/TCP FC 0x01, address 0 (PLC address 1)"
params: []
- id: modbus_write_relay1
label: Modbus Write Relay 1
kind: action
command: "Modbus/TCP FC 0x05, address 0 (PLC address 1); 0x00=Off, 0xFF=On"
params: []
- id: modbus_write_multiple_relays
label: Modbus Write Multiple Relays
kind: action
command: "Modbus/TCP FC 0x0F, address 0 (PLC address 1) for multiple relays"
params: []
- id: modbus_pulse_relay1
label: Modbus Pulse Relay 1
kind: action
command: "Modbus/TCP FC 0x16, address 512-513 (PLC address 40513-40514); 32-bit float = pulse duration in seconds"
params:
- name: duration
type: number
description: Pulse duration in seconds, written as IEEE 754 32-bit float
- id: modbus_read_digital_input1
label: Modbus Read Digital Input 1
kind: query
command: "Modbus/TCP FC 0x02, address 1 (PLC address 10002)"
params: []
- id: modbus_read_analog_input1
label: Modbus Read Analog Input 1
kind: query
command: "Modbus/TCP FC 0x03, address 4-5 (PLC address 40005-40006); 32-bit float"
params: []
- id: modbus_read_vin
label: Modbus Read Vin
kind: query
command: "Modbus/TCP FC 0x03, address 6-7 (PLC address 40007-40008); 32-bit float"
params: []
- id: modbus_read_temp_sensor
label: Modbus Read Temperature Sensor
kind: query
command: "Modbus/TCP FC 0x03, address 8-9 (PLC address 40009-40010); 32-bit float"
params: []
- id: modbus_read_internal_register
label: Modbus Read Internal Register
kind: query
command: "Modbus/TCP FC 0x03, address 10-11 (PLC address 40011-40012); 32-bit float"
params: []
- id: modbus_write_internal_register
label: Modbus Write Internal Register
kind: action
command: "Modbus/TCP FC 0x16, address 10-11 (PLC address 40011-40012); 32-bit float"
params:
- name: value
type: number
description: Register value as IEEE 754 32-bit float
# === SNMP (Section 3) ===
- id: snmp_get_request
label: SNMP GetRequest
kind: query
command: "SNMP GetRequest PDU against configured I/O OID (MIB generated from Setup > Advanced Network > Generate and Download MIB File)"
params:
- name: oid
type: string
description: Object identifier for the target I/O (from generated MIB)
- id: snmp_get_next_request
label: SNMP GetNextRequest
kind: query
command: "SNMP GetNextRequest PDU; returns next object in MIB walk"
params: []
- id: snmp_get_bulk_request
label: SNMP GetBulkRequest
kind: query
command: "SNMP GetBulkRequest PDU; bulk transfer of consecutive objects"
params: []
- id: snmp_set_request
label: SNMP SetRequest
kind: action
command: "SNMP SetRequest PDU to control/monitor configured I/O; write community string required (default 'webrelay') for V1/V2c"
params:
- name: oid
type: string
description: Object identifier for the target I/O (from generated MIB)
- name: value
type: string
description: Value to set
- id: snmp_get_sysdescr
label: SNMP Get system.sysDescr
kind: query
command: "SNMP GetRequest _system.sysDescr_ (RFC1213); response 'X-4xx'"
params: []
- id: snmp_get_sysobjectid
label: SNMP Get system.sysObjectID
kind: query
command: "SNMP GetRequest _system.sysObjectID_ (RFC1213); response 'X4xx'"
params: []
- id: snmp_get_sysuptime
label: SNMP Get system.sysUpTime
kind: query
command: "SNMP GetRequest _system.sysUpTime_ (RFC1213); response = time in hundredths of seconds since last powered"
params: []
- id: snmp_get_sysname
label: SNMP Get system.sysName
kind: query
command: "SNMP GetRequest _system.sysName_ (RFC1213); response 'X-4xx*'"
params: []
# === MQTT (Section 4) ===
- id: mqtt_subscribe
label: MQTT Subscribe to Broker
kind: action
command: "MQTT 3.1.1 SUBSCRIBE to broker defined in Broker tab; device receives I/O info published by another device"
params:
- name: topic
type: string
description: Broker topic to subscribe to
- id: mqtt_publish
label: MQTT Publish to Broker
kind: action
command: "MQTT 3.1.1 PUBLISH to broker defined in Broker tab; device sends I/O info (payload tokens substituted, e.g. ${relay1}, ${vin})"
params:
- name: topic
type: string
description: Broker topic to publish to
- id: mqtt_sparkplug_b_publish
label: MQTT Sparkplug B Publish
kind: action
command: "Sparkplug B publish; structured topic naming and payload format (alternative to standard MQTT)"
params: []
# === Remote Services / External Server (Section 5) ===
- id: direct_server_control
label: Direct Server Control (server-initiated TCP)
kind: action
command: "External server opens TCP connection to device, sends commands and/or reads state, then closes connection"
params: []
- id: remote_services_connect
label: Remote Services Connection (device-initiated TCP V1)
kind: action
command: "Device initiates TCP V1 connection to external server per Connection Interval (Advanced Network tab); sends Connection String ending with state.xml"
params: []
- id: remote_services_ack
label: Remote Services ACK Response
kind: action
command: "External server sends 3-character 'ACK' in response to each connection string; if not received within 10s the device closes the connection"
params: []
- id: remote_services_send_state
label: Remote Services Send state.xml on Event
kind: action
command: "On a logic event with a send-state action to remote server, state.xml is sent over the open connection"
params: []
# Note: TCP V2.0 reserved for ControlByWeb.Cloud, not for other use.
# === ControlByWeb Cloud DAT URL API (Section 6) ===
- id: cloud_dat_read_state_json
label: Read state via Cloud DAT URL
kind: query
command: "GET https://api.controlbyweb.cloud/{datUrl}/state.json HTTP/1.1\r\n\r\n"
params:
- name: datUrl
type: string
description: ControlByWeb Cloud-generated DAT URL token
- id: cloud_dat_read_state_xml
label: Read state.xml via Cloud DAT URL
kind: query
command: "GET https://api.controlbyweb.cloud/{datUrl}/state.xml HTTP/1.1\r\n\r\n"
params:
- name: datUrl
type: string
description: ControlByWeb Cloud-generated DAT URL token
- id: cloud_dat_set_relays
label: Set multiple relays via Cloud DAT URL
kind: action
command: "GET https://api.controlbyweb.cloud/{datUrl}/state.json?relay1={r1}&relay2={r2} HTTP/1.1\r\n\r\n"
params:
- name: datUrl
type: string
description: ControlByWeb Cloud-generated DAT URL token
- name: r1
type: integer
description: Relay 1 value (0/1)
- name: r2
type: integer
description: Relay 2 value (0/1)
Feedbacks
- id: relay1_state
type: enum
values: [0, 1] # 0=off (coil off), 1=on (coil energized); source also accepts 2 for pulse trigger
- id: relay2_state
type: enum
values: [0, 1]
- id: digital_input
type: enum
values: [0, 1] # 0=off (voltage not applied), 1=on (voltage applied)
- id: digital_io
type: enum
values: [0, 1] # digitalIOX: 0=off (voltage not applied), 1=on (voltage applied); configurable as input or output
- id: analog_input
type: number
values: [] # Value of analog input X (UNRESOLVED: range/units not stated)
- id: onewire_sensor
type: number
values: [] # oneWireSensorX: "x.x" = sensor unreadable; numeric = current value; with showUnits=1 appends unit (e.g. "77.3 F")
- id: frequency_input
type: number
values: [] # frequencyInput: value of the X-420 frequency input
- id: vin
type: number
values: [] # Scaled internal Vin measurement (UNRESOLVED: units/scale not stated)
- id: register_value
type: number
values: [] # Value of register X
- id: on_time
type: number
values: [] # Seconds input has been on since last coming on
- id: total_on_time
type: number
values: [] # Total seconds input has been on
- id: count
type: number
values: [] # Count value associated with input X
- id: frequency
type: number
values: [] # Frequency associated with input X
- id: latitude
type: number
values: [] # lat (appears in state.json example)
- id: longitude
type: number
values: [] # long (appears in state.json example)
- id: min_rec_refresh
type: integer
values: [] # minRecRefresh (appears in state.json example)
- id: utc_time
type: integer
values: [] # Seconds since January 1st, 1970
- id: timezone_offset
type: integer
values: [] # Offset for utcTime to local time
- id: serial_number
type: string
values: [] # Format 00:00:00:00:00:00
Variables
- id: register1
type: number
description: Internal register settable via state.xml?register1= or customState.xml?{name}=
Events
- id: snmp_trap
type: unsolicited
description: "SNMP Trap sent when a relay changes state, a sensor value reaches a particular value, or supply voltage goes out of desired range. Configured as actions in Conditional and Scheduled tasks."
- id: snmp_notification
type: unsolicited
description: "SNMP Notification (SNMP V2c/V3); similar to trap but requires response from SNMP manager. Retries occur if manager does not respond."
# UNRESOLVED: HTTP request/response model only; no other unsolicited push notifications documented for WebRelay Wireless over HTTP.
Macros
# UNRESOLVED: source does not document any multi-step macro sequences.
Safety
confirmation_required_for: []
interlocks:
- "Modbus communications are disabled whenever the User account is enabled (Modbus/TCP has no password mechanism). Disable User account before using Modbus/TCP."
- "SNMP write operations (SetRequest) require the write community string (default 'webrelay') for V1/V2c; SNMP V3 uses USM auth/privacy."
# UNRESOLVED: source contains no explicit safety warnings, interlocks, or power-on sequencing requirements for the WebRelay Wireless.
Notes
The source describes the ControlByWeb 400 Series platform broadly; the WebRelay Wireless is mentioned in the device name but the model-specific I/O count, exact relay count, and which subset of XML/JSON tags apply to a Wireless variant are not explicitly enumerated. The relay control table in section 1.1.2 lists relay1 and relay2 as examples; the XML state example (section 1.2) and MQTT payload token table (section 4.1.4) show relay1-relay4 and digitalInput1-digitalInput4, suggesting up to 4 relays/inputs on the platform — refer to the device's Modbus address map (generated from the Setup pages) for authoritative I/O addressing.
When the User account is enabled on the device, requests must include Authorization: Basic <base64(name:password)> per section 1.1 ("Password Enabled"); the documented default credential is none:webrelay (Base64 bm9uZTp3ZWJyZWxheQ==). When Modbus/TCP is used (port 502 by default), the User account must be disabled because Modbus has no password mechanism. The pulseTime query parameter must precede the relay=2 parameter in the URL. Modbus/TCP supports two simultaneous TCP sockets; connections time out after 50 seconds of inactivity (a periodic read keeps them open). Modbus errors return function code + 0x80 with exception codes 0x01 (not supported), 0x02 (bad address/quantity), 0x03 (padding/byte count). Modbus 32-bit floats are read/written in register pairs (quantity must be even); endianness is configurable in Advanced Network. A sensor not installed returns 0xFFFFFFFF (NaN).
MQTT payload tokens documented (section 4.1.4) for use in published payloads: ${mac}, ${ver} (firmware revision), ${ser}, ${uptime}, ${ip}, ${port} (HTTP), ${httpsport}, ${dateTime}, ${name}, ${model}, ${clientID}, ${digitalInput1}-${digitalInput4}, ${relay1}-${relay4}, ${vin}, ${register1}. Remote Services uses TCP V1 (device-initiated); TCP V2.0 is reserved for ControlByWeb.Cloud and not for other use. Cloud DAT URLs facilitate 3rd-party integration but not peer-to-peer device communication.
Upgrade pass done. Preserved all original IDs/shapes. Added: SNMP (8 actions + 2 events), MQTT (3 actions), Remote Services (4 actions), Modbus concrete-address examples (9 actions), showUnits read variants (2), cloud DAT state.xml read (1), missing feedbacks (digital_io, onewire_sensor, frequency_input, latitude, longitude, min_rec_refresh), Modbus interlock + SNMP write interlock in Safety, udp protocol + port 502 note in Transport.
## Provenance
```yaml
source_domains:
- controlbyweb.com
source_urls:
- https://controlbyweb.com/wp-content/uploads/2025/05/cbw-integration-and-protocols-manual.pdf
- https://controlbyweb.com/support/cbw-integration-manual/
- https://controlbyweb.com/webrelay-wireless/
- https://controlbyweb.com/wp-content/uploads/2024/02/webrelay-wireless-users-manual.pdf
retrieved_at: 2026-06-30T15:19:33.476Z
last_checked_at: 2026-07-21T21:46:27.032Z
```
## Verification Summary
```yaml
verdict: verified
checked_at: 2026-07-21T21:46:27.032Z
matched_actions: 60
action_count: 60
confidence: medium
summary: "All 60 spec actions matched literal source documentation; transport parameters (HTTP port 80, Modbus 502, Basic auth) verified; coverage ratio 60/63 > 0.9 threshold. (7 unresolved item(s) noted in Known Gaps.)"
```
## Known Gaps
```yaml
- "source describes the ControlByWeb 400 Series platform broadly; the WebRelay Wireless model-specific I/O count, relay count, and which XML/JSON tags apply to a Wireless variant are not explicitly enumerated."
- "range/units not stated)"
- "units/scale not stated)"
- "HTTP request/response model only; no other unsolicited push notifications documented for WebRelay Wireless over HTTP."
- "source does not document any multi-step macro sequences."
- "source contains no explicit safety warnings, interlocks, or power-on sequencing requirements for the WebRelay Wireless."
- "default TCP port for WebRelay Wireless HTTP server — source mentions 80 implicitly via \"not port 80\" alternative example at :8000, but default is not explicitly stated for this model. UNRESOLVED: SNMP transport layer (UDP assumed by convention) and port (conventionally 161) not explicitly stated. UNRESOLVED: MQTT broker port not stated. UNRESOLVED: WebRelay Wireless-specific relay count and full local I/O tag list. UNRESOLVED: firmware version compatibility range not stated in source. UNRESOLVED: SNMP V3 USM algorithm/credential formats not specified beyond general description."
```
---
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0