Summary

The ControlByWeb X16S is a network-attached relay/digital-I/O controller. The X-400 Series (parent family documented in the source) exposes a built-in web server that responds to HTTP GET requests, speaks Modbus/TCP on port 502, supports SNMP v1/v2c/v3, and can publish/subscribe via MQTT 3.1.1 (and Sparkplug B). This spec covers the four transport interfaces and the query/control operations explicitly documented in the source.

Transport

protocols:
  - tcp
  - http
addressing:
  port: 80
  base_url: "/"  # example: http://192.168.1.2/state.xml
  notes: "HTTP default port 80 shown in source examples; port 8000 shown as alternate when TCP port has been changed. Modbus/TCP uses port 502. MQTT broker port, SNMP port, and Remote Services TCP port not stated."
auth:
  type: basic  # optional; HTTP requests are unauthenticated when User account is disabled
  notes: "If User account is enabled, requests must include `Authorization: Basic <base64(user:password)>` header. Default credential sample in source: none:webrelay -> bm9uZTp3ZWJyZWxheQ==. Modbus is disabled when User account is enabled. SNMP v1/v2c community strings default to `webrelay`; SNMP v3 uses USM with configurable auth/privacy algorithm and password."
protocols:
  - tcp  # Modbus/TCP slave (port 502; configurable under Advanced Network tab)

Traits

- powerable       # inferred from relay on/off/pulse commands
- routable        # inferred from per-relay and per-input addressing
- queryable       # inferred from state.xml/json read operations
- levelable       # inferred from register/analog-input set value commands

Actions

- id: get_state_xml
  label: Get Device State (XML)
  kind: query
  command: "GET /state.xml HTTP/1.1\r\n\r\n"
  params: []
  notes: "Returns datavalues XML block; only I/O with a 'Local I/O Number' assigned appear in state.xml."

- id: get_state_json
  label: Get Device State (JSON)
  kind: query
  command: "GET /state.json HTTP/1.1\r\n\r\n"
  params: []

- id: get_custom_state_xml
  label: Get Custom State (XML)
  kind: query
  command: "GET /customState.xml HTTP/1.1\r\n\r\n"
  params: []
  notes: "Tag names are camelCase versions of user-configured I/O names."

- id: get_custom_state_json
  label: Get Custom State (JSON)
  kind: query
  command: "GET /customState.json HTTP/1.1\r\n\r\n"
  params: []

- id: relay_off
  label: Turn Relay N OFF
  kind: action
  command: "GET /state.xml?relay{n}=0 HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
      description: Relay number (1-based)

- id: relay_on
  label: Turn Relay N ON
  kind: action
  command: "GET /state.xml?relay{n}=1 HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
      description: Relay number (1-based)

- id: relay_pulse
  label: Pulse Relay N (default duration)
  kind: action
  command: "GET /state.xml?relay{n}=2 HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
      description: Relay number (1-based)
  notes: "Pulses for the Pulse Duration configured in relay setup page (1.5s in source example)."

- id: relay_pulse_custom
  label: Pulse Relay N (custom duration)
  kind: action
  command: "GET /state.xml?pulseTime{n}={seconds}&relay{n}=2 HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
      description: Relay number (1-based)
    - name: seconds
      type: integer
      description: Pulse duration in seconds; MUST appear in query string before relay{n}=2

- id: set_on_time
  label: Set On Time for Input N
  kind: action
  command: "GET /state.xml?onTime{n}={value} HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
    - name: value
      type: number

- id: set_total_on_time
  label: Set Total On Time for Input N
  kind: action
  command: "GET /state.xml?totalOnTime{n}={value} HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
    - name: value
      type: number

- id: set_counter
  label: Set Counter N
  kind: action
  command: "GET /state.xml?count{n}={value} HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
    - name: value
      type: number

- id: set_register
  label: Set Register N
  kind: action
  command: "GET /state.xml?register{n}={value} HTTP/1.1\r\n\r\n"
  params:
    - name: n
      type: integer
    - name: value
      type: number
  notes: "Source example: register1=10.5"

- id: multi_command
  label: Multi-Command (combine args)
  kind: action
  command: "GET /state.xml?relay1=1&relay2=0 HTTP/1.1\r\n\r\n"
  params: []

- id: get_log_txt
  label: Read Data Log
  kind: query
  command: "GET /log.txt HTTP/1.1\r\n\r\n"
  params: []
  notes: "Requires password if User account enabled."

- id: erase_log_txt
  label: Erase Data Log
  kind: action
  command: "GET /log.txt?erase=1 HTTP/1.1\r\n\r\n"
  params: []

- id: get_syslog_txt
  label: Read System Log
  kind: query
  command: "GET /syslog.txt HTTP/1.1\r\n\r\n"
  params: []
  notes: "Format: MM/DD/YYYY HH:MM:SS, (category): (message). Requires setup username and password."

- id: erase_syslog_txt
  label: Erase System Log
  kind: action
  command: "GET /syslog.txt?erase=1 HTTP/1.1\r\n\r\n"
  params: []

- id: modbus_read_coils
  label: Modbus Read Coils (FC 01)
  kind: query
  command: "Modbus FC 0x01"
  params:
    - name: start_address
      type: integer
      description: Refer to Modbus address map in setup pages
    - name: coil_quantity
      type: integer
  notes: "1 bit per coil; '1' = ON, '0' = OFF. Error code: 0x81, exception 0x02."

- id: modbus_read_discrete_inputs
  label: Modbus Read Discrete Inputs (FC 02)
  kind: query
  command: "Modbus FC 0x02"
  params:
    - name: start_address
      type: integer
    - name: input_quantity
      type: integer
  notes: "Error code: 0x82, exception 0x02."

- id: modbus_read_holding_registers
  label: Modbus Read Holding Registers (FC 03)
  kind: query
  command: "Modbus FC 0x03"
  params:
    - name: start_address
      type: integer
    - name: input_quantity
      type: integer
      description: Must be even; 32-bit values read in pairs
  notes: "32-bit IEEE 754 floats. Endianness configurable. Little-endian example 0x800042A2 = 81.25. Sensor missing returns 0xFFFFFFFF (NaN). Error code: 0x83, exception 0x02."

- id: modbus_write_single_coil
  label: Modbus Write Single Coil (FC 05)
  kind: action
  command: "Modbus FC 0x05, output_value=0x00 (off) | 0xFF (on)"
  params:
    - name: start_address
      type: integer
    - name: output_value
      type: integer
      description: "0x00 (off) or 0xFF (on)"
  notes: "Response mirrors requested state. Error code: 0x85; exceptions 0x01, 0x02, 0x03."

- id: modbus_write_multiple_coils
  label: Modbus Write Multiple Coils (FC 15)
  kind: action
  command: "Modbus FC 0x0F"
  params:
    - name: start_address
      type: integer
    - name: output_quantity
      type: integer
      description: byte count = quantity/8
    - name: output_value
      type: integer
      description: "Bit pattern 0x0000-0xFFFF (e.g. 0xF0 turns off first 4 outputs, on outputs 5-8)"
  notes: "Error code: 0x8F; exceptions 0x01, 0x02, 0x03."

- id: modbus_write_multiple_registers
  label: Modbus Write Multiple Registers (FC 16)
  kind: action
  command: "Modbus FC 0x10"
  params:
    - name: start_address
      type: integer
    - name: input_quantity
      type: integer
      description: Must be even; 32-bit values in pairs
    - name: values
      type: number
      description: IEEE 754 floats
  notes: "Acknowledged by echoing register quantity. Error code: 0x90; exceptions 0x01, 0x02."

- id: modbus_pulse_relay
  label: Modbus Pulse Relay (FC 16, 32-bit float)
  kind: action
  command: "Modbus FC 0x16, address 512-513 (PLC 40513-40514), value = pulse duration in seconds (32-bit float)"
  params:
    - name: relay
      type: integer
    - name: seconds
      type: number
  notes: "Source example is Relay 1."

- id: snmp_get
  label: SNMP GetRequest
  kind: query
  command: "SNMP GetRequest"
  params: []
  notes: "Supports v1, v2c, v3. RFC1213 objects: sysDescr (X-4xx), sysObjectID (X4xx), sysUpTime, sysName (X-4xx*). Module I/O via generated MIB file."

- id: snmp_set
  label: SNMP SetRequest
  kind: action
  command: "SNMP SetRequest"
  params: []
  notes: "Community strings default to `webrelay` for v1/v2c; v3 uses USM."

- id: snmp_trap
  label: SNMP Trap
  kind: action
  command: "SNMP Trap"
  params: []
  notes: "Triggers configured under Conditional and Scheduled tasks (relay change, sensor threshold, supply voltage out of range)."

- id: snmp_notification
  label: SNMP Notification
  kind: action
  command: "SNMP Notification"
  params: []
  notes: "SNMP v2c/v3 only. Requires response from manager; retries if no response."

- id: mqtt_publish
  label: MQTT Publish
  kind: action
  command: "MQTT PUBLISH"
  params: []
  notes: "MQTT 3.1.1. Broker defined in Broker tab. Payload tokens: ${mac}, ${ver}, ${ser}, ${uptime}, ${ip}, ${port}, ${httpsport}, ${dateTime}, ${name}, ${model}, ${clientID}, ${digitalInput1..4}, ${relay1..4}, ${vin}, ${register1}."

- id: mqtt_subscribe
  label: MQTT Subscribe
  kind: action
  command: "MQTT SUBSCRIBE"
  params: []
  notes: "Subscribes to broker defined in Broker tab to receive I/O information from other devices."

- id: sparkplug_b_publish
  label: Sparkplug B Publish
  kind: action
  command: "Sparkplug B PUBLISH"
  params: []

- id: remote_services_connect
  label: Remote Services Connect
  kind: action
  command: "Remote Services TCP V1 connection (initiated by device)"
  params: []
  notes: "Device opens TCP V1 connection at configured Connection Interval. Sends Connection String (static info + user-defined string + state.xml). Expects 3-char `ACK` within 10 seconds. Version 2.0 reserved for ControlByWeb.Cloud."

- id: cloud_dat_url_get
  label: Cloud DAT URL State Read
  kind: query
  command: "GET https://api.controlbyweb.cloud/{dat_url}/state.json HTTP/1.1\r\n\r\n"
  params: []
  notes: "Login at http://www.ControlByWeb.Cloud required."

- id: cloud_dat_url_control
  label: Cloud DAT URL Multi-Relay Control
  kind: action
  command: "GET https://api.controlbyweb.cloud/{dat_url}/state.json?relay1=1&relay2=1 HTTP/1.1\r\n\r\n"
  params: []
  notes: "Triggers multiple relays in one command; no port forwarding needed."

Feedbacks

- id: digital_input
  type: enum
  values: [0, 1]
  source_tag: "digitalInputX"

- id: on_time
  type: number
  source_tag: "onTimeX"

- id: total_on_time
  type: number
  source_tag: "totalOnTimeX"

- id: count
  type: number
  source_tag: "countX"

- id: frequency
  type: number
  source_tag: "frequencyX"

- id: relay_state
  type: enum
  values: [0, 1]
  description: "0 = off (coil off), 1 = on (coil energized)"
  source_tag: "relayX"

- id: digital_io
  type: enum
  values: [0, 1]
  source_tag: "digitalIOX"

- id: analog_input
  type: number
  source_tag: "analogInputX"

- id: vin
  type: number
  description: "Scaled internal Vin measurement"
  source_tag: "vin"

- id: frequency_input
  type: number
  source_tag: "frequencyInput"

- id: register
  type: number
  source_tag: "registerX"

- id: utc_time
  type: integer
  description: "Seconds since 1970-01-01"
  source_tag: "utcTime"

- id: onewire_sensor
  type: string
  source_tag: "oneWireSensorX"

- id: timezone_offset
  type: integer
  source_tag: "timezoneOffset"

- id: serial_number
  type: string
  source_tag: "serialNumber"

Variables

- id: register_value
  type: number
  description: "Writable numeric register; settable via state.xml?register{n}={value}"
  range: "UNRESOLVED: range not stated in source"

Events

- id: snmp_trap_relay_change
  description: "SNMP trap on relay state change (configurable)"
- id: snmp_trap_sensor_threshold
  description: "SNMP trap when sensor value reaches a configured threshold"
- id: snmp_trap_vin_range
  description: "SNMP trap when supply voltage is out of configured range"
- id: syslog_event
  description: "MM/DD/YYYY HH:MM:SS, (category): (message) - read from syslog.txt"

Macros

# UNRESOLVED: source does not document explicit multi-step user-defined sequences.

Safety

confirmation_required_for: []
interlocks: []
# UNRESOLVED: source contains no explicit safety warnings, interlock procedures, or power-on sequencing requirements.

Notes

  • Source documents the X-400 Series generically (relay1..relay4 examples). X16S-specific I/O counts NOT stated.
  • HTTP default port 80. Port 8000 shown as alternate when TCP port has been changed.
  • User account enabled: HTTP requires Authorization: Basic <base64(user:password)>. Example: none:webrelay -> bm9uZTp3ZWJyZWxheQ==. When enabled, Modbus/TCP is disabled.
  • Modbus/TCP port 502, 2 TCP sockets, 50s idle timeout.
  • Modbus error response: function code + 0x80. Exceptions 0x01 (unsupported), 0x02 (bad address/quantity).
  • SNMP community strings default to webrelay. v3 uses USM.
  • MQTT 3.1.1 only. Sparkplug B = defined topic/payload structure.
  • Remote Services: device-initiated outbound TCP V1; expects 3-char ACK within 10s.
  • ControlByWeb.Cloud DAT URLs: no port forwarding; no peer-to-peer.

Provenance

source_domains:
  - controlbyweb.com
source_urls:
  - https://controlbyweb.com/wp-content/uploads/2025/05/cbw-integration-and-protocols-manual.pdf
  - https://controlbyweb.com/wp-content/uploads/2024/01/X-16S_manual_v1.1.pdf
  - https://controlbyweb.com/support/cbw-integration-manual/
  - https://controlbyweb.com/support/manuals/x-400-users-manual/
  - https://controlbyweb.com/support/
retrieved_at: 2026-06-30T15:03:06.654Z
last_checked_at: 2026-07-07T11:11:04.229Z

Verification Summary

verdict: verified
checked_at: 2026-07-07T11:11:04.229Z
matched_actions: 34
action_count: 34
confidence: medium
summary: "All 34 spec actions verified verbatim against source; HTTP, Modbus, SNMP, MQTT, Sparkplug B, Remote Services, and Cloud APIs fully represented. (5 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "source describes the X-400 Series generically with relay1..relay4 examples; the X16S-specific I/O map, relay count, digital input count, analog input count, and 1-Wire sensor count are not enumerated in the source."
- "range not stated in source\""
- "source does not document explicit multi-step user-defined sequences."
- "source contains no explicit safety warnings, interlock procedures, or power-on sequencing requirements."
- "X16S-specific I/O map (relay count, digital input count, analog input count, register count, 1-Wire sensor count) is not enumerated in source. Modbus address map references \"Refer to Modbus address map in setup pages\" generically."

From the AI4AV catalog (https://ai4av.net) · ODbL-1.0