Skip to content

Gateway Configuration ​

Development Preview

This page is based on the runtime parsers at commit b1a16cbc (GatewayConfig, TagConfig::fromJson, etc.) and the active callbacks. It also includes keys from the project configuration documents that the runtime does not read yet, clearly marked as such. Writing configuration does not mean drivers are registered or end-to-end functionality is verified.

1. Configuration File and How It Takes Effect ​

The main configuration file defaults to config/gateway.json, and the process specifies its path with --config. If the configuration file does not exist, it is created automatically with built-in defaults; on load, the file contents override the defaults (merge); on save, a temporary file is written first and then atomically renamed, avoiding corruption from power loss.

The following keys are read directly by the current code:

KeyCurrent purpose
web.portHTTP port for the Web UI/API, default 8080
system.logLevelLog level, such as trace, debug, info, warn, error
mqtt.broker / mqtt.portBroker host and port; the host name carries no tcp:// or ssl:// prefix
mqtt.clientIdMQTT Client ID
mqtt.username / mqtt.passwordBroker authentication credentials
mqtt.productId / mqtt.deviceNumProduct/device segments of the property-reporting and function topics
mqtt.keepAliveSecMQTT Keep Alive seconds, default 60
mqtt.connectTimeoutMsConnection timeout (milliseconds), default 10000
mqtt.cleanSessionMQTT Clean Session, default true
mqtt.qosPublish and subscribe QoS, default 1
mqtt.tlsWhether to use an ssl:// connection; the certificate fields must be configured correctly and separately
mqtt.caCert / mqtt.clientCert / mqtt.clientKeyOptional TLS CA, client certificate, and private key paths
mqtt.autoReconnect / mqtt.reconnectIntervalMs / mqtt.maxReconnectAttemptsPaho client auto-reconnect options and base interval; not a production disconnected-data guarantee
driversTop-level driver configuration array, see section 4
engine.defaultPollMs / engine.maxTags / engine.batchSizeTagEngine default polling interval, Tag limit, and batch size
alertManager.maxHistoryDays / alertManager.maxActiveAlerts / alertManager.deduplicateEnabledAlarm history retention days (30), maximum active alarms (1000), and alarm deduplication
ota.versionApiUrl / ota.binaryPathOTA version check URL and executable file path
certificates.certDir / certificates.enabledTLS certificate directory and switch

PUT /api/mqtt/config currently only handles broker, port, clientId, username, and password, then saves the configuration; it does not reconnect automatically as the Web wording suggests. A complete MQTT change should edit the real configuration and restart the process, after first resolving the read-only mount issue in deployment.

2. Default Configuration Keys Not Yet Read by the Runtime ​

The repository's default config/gateway.json also contains the following keys. They come from the design goals in the project configuration documents, but the current GatewayConfig runtime code has no reader for them — do not treat these keys as effective configuration:

  • gateway.name / gateway.webPort / gateway.logLevel / gateway.dataDir: legacy key names; the actively read keys are web.port and system.logLevel.
  • network.* (wifiMode/wifiSsid/apSsid, etc.): design configuration for WiFi/AP provisioning; currently the responsibility of the NetworkManager module, and how it takes effect depends on that module's implementation.
  • cache.* (enabled/maxRecords/maxSizeMB/dbPath): design configuration for offline caching; SqliteCache is constructed but not wired into the active reporting path.
  • engine.defaultPollIntervalMs / engine.reportIntervalMs / engine.batchMergeEnabled: engine extension design keys; the actively read keys are engine.defaultPollMs and the others above.
  • mqtt.reconnectMinSec / mqtt.reconnectMaxSec: exponential backoff design keys; the actively read key is mqtt.reconnectIntervalMs.
  • Environment-variable overrides such as FASTBEE_MQTT_*, FASTBEE_WEB_PORT, and FASTBEE_LOG_LEVEL, as well as configuration hot reload, are design goals with no complete implementation at present; TZ in Compose should not be extrapolated into a general configuration override mechanism.

3. Configuration Encryption and Secrets Management ​

At startup, AES encryption support is enabled for the configuration (ConfigCrypto): sensitive fields in the configuration file are stored as ENC(...) ciphertext, decrypted on load and encrypted on save. The key file is .secret.key in the configuration directory (created automatically on first startup).

  • When backing up ciphertext configuration, the key must be protected in sync according to the security policy, and it must never be committed to a public repository.
  • ENC(...) ciphertext depends on the matching key and cannot be ported across environments; replace it with the credentials of the local environment when deploying.
  • Compose's read-only config mount blocks key creation and API saves; this must be explicitly resolved in the deployment design.
  • The default admin/admin123 must be changed immediately; anonymous Mosquitto is only acceptable in an isolated development environment.

4. Driver Configuration (the drivers Array) ​

The runtime reads the following fields from the top-level drivers array (compatible legacy keys are noted):

FieldDescription
protocolNameProtocol name; modbus in the Modbus example, default modbus
connectionTypetcp or rtu, default tcp
host / portTCP target address and port, default 127.0.0.1:502
serialDeviceRTU serial device path; the legacy key serialPort is also accepted
baudRateSerial baud rate, default 9600; the legacy key baudrate is also accepted
parityInteger parity: 0=N, 1=O, 2=E
dataBits / stopBitsSerial data bits (8) and stop bits (1); lowercase legacy keys are also accepted
timeoutMs / retryCountRequest timeout (3000ms) and retry count (3)
pollIntervalMsDriver polling interval (1000ms)

TCP example:

json
{
  "drivers": [
    {
      "protocolName": "modbus",
      "connectionType": "tcp",
      "host": "192.0.2.10",
      "port": 502,
      "timeoutMs": 3000,
      "retryCount": 3,
      "pollIntervalMs": 1000
    }
  ]
}

192.0.2.10 is a documentation-only reserved address. Real libmodbus driver code exists, but the current application only loads and logs these configurations; it does not create, initialize, or register drivers, and other protocols cannot bypass this shared blocker either. OPC UA is optional/under development only; BACnet, IEC104, S7, and DLT645 should currently all be treated as Stub/integration-in-progress boundaries — see sections 7 and 8 of the overview.

5. Device and Tag Fields ​

5.1 Sub-devices ​

POST /api/devices and PUT /api/devices/:id currently parse:

  • deviceId: internal unique ID; dev-<timestamp> is generated when it is empty on creation.
  • productId, deviceNum, deviceName: product, device number, and display name.
  • protocolType: protocol type, such as modbus.
  • online, lastHeartbeat: serializable status fields; they must not be treated as a physical online guarantee.

The id, protocol, slaveAddress, and similar fields the Web currently sends/displays are inconsistent with the runtime; do not infer the API model from the interface.

5.2 Tag Fields ​

POST /api/devices/:id/tags uses TagConfig::fromJson(). The fields actually parsed:

FieldDescription
id, nameTag identifier and display name; deviceId is overridden by the device ID in the route
sourceTypeNumeric source type: 0=MODBUS, 1=OPCUA, 2=BACNET, 3=IEC104, 4=DLT645, 5=S7, plus 10/11/12=GPIO_DI/DO/AI and 20=SYSTEM
slaveAddr, registerAddr, registerCountModbus slave address, zero-based register address, and register count
scale, offset, unitLinear scaling factor, offset, and engineering unit
scaleType, sqrtFactorScaling type: 0=NONE, 1=LINEAR, 2=SQRT, 3=CUSTOM; the coefficient for SQRT mode
pollIntervalMs, deadband, reportOnChange, enabledSampling period (ms), deadband value, report-on-change, and enable switch
nodeIdOPC UA node ID (e.g. ns=2;s=Temperature)
objectType, instanceId, propertyIdBACnet object type, instance number, and property ID
gpioChannelGPIO channel number

Notes:

  • registerAddr is a zero-based address passed directly to libmodbus; use 0 for the first holding register rather than writing 40001 directly.
  • The current request parser does not read the dataType, function/functionCode, byteOrder, or pollInterval fields (byteOrder is always the default big-endian), even though responses may serialize dataType; configuration acceptance must check the fields actually read.
  • Scaling conversion takes effect at the driver layer: for LINEAR, engineering value = raw value × scale + offset; for SQRT, engineering value = √(raw value) × sqrtFactor; reverse conversion (control downlink) is only supported for LINEAR.

6. GPIO Configuration (gpio.json) ​

GPIO channel configuration is independent of the main configuration and is read by GpioManager; field details depend on its runtime implementation. The example structure given in the project documents:

json
{
  "di":  [{"channel": 0, "name": "door_sensor", "productId": "P003", "propertyId": "door"}],
  "do":  [{"channel": 0, "name": "relay_1", "productId": "P003", "propertyId": "relay"}],
  "ai":  [{"channel": 0, "name": "temp_sensor", "range": [4, 20], "unit": "mA", "engMin": 0, "engMax": 100}],
  "led": [{"name": "power", "gpio": 17}, {"name": "network", "gpio": 27}, {"name": "fault", "gpio": 22}]
}

Real GPIO requires compiling with -DFASTBEE_ENABLE_GPIO=ON and installing libgpiod; otherwise a simulated backend is used. For the stronger pin-based peripheral model (DI/DO/AI/AO/LED/buzzer/watchdog), see Peripherals and Linkage.

7. MQTT Topics and Active Data Formats ​

Property reporting topic:

text
/{productId}/{deviceNum}/property/post

Function subscription primitive topic (not currently called by production code):

text
/{productId}/{deviceNum}/function/#

The JSON structure used by the active reporting callback:

json
{
  "deviceId": "modbus-dev-001",
  "timestamp": 1700000000000,
  "tags": [
    { "id": "holding-0", "value": 25.5, "quality": 0 }
  ]
}

quality values: 0=GOOD, 1=BAD, 2=UNCERTAIN, 3=TIMEOUT, 4=NOT_CONNECTED, 5=CONFIG_ERROR.

There is also a TagMapper::buildPropertyPost() that is not wired into the active callback and produces a different params format. At present, distinguish "mappers that exist in the code" from "the actual active reporting format". When MQTT is disconnected, the active callback skips the batch; constructing SqliteCache and setting the cache configuration does not mean offline replay is working, and production code does not call the function subscription either.

8. Alarm Rules and Aggregation Rules ​

Alarm rules are configured dynamically through the REST API (POST /api/alarms/rules) without modifying the configuration file. Rule JSON structure:

json
{
  "id": "high-temp",
  "name": "high-temp alarm",
  "tagId": "temp1",
  "type": "LEVEL",
  "enabled": true,
  "severity": "HIGH",
  "hEnabled": true,
  "highLimit": 80.0,
  "hhEnabled": true,
  "highHighLimit": 95.0,
  "lEnabled": true,
  "lowLimit": 10.0,
  "deadband": 2.0
}
FieldDescription
typeAlarm type: LEVEL/DEVIATION/RATE_OF_CHANGE/QUALITY/DIGITAL
severitySeverity level: LOW/MEDIUM/HIGH/CRITICAL
highLimit / lowLimitHigh/low thresholds (LEVEL type, supporting the four levels HH/H/L/LL)
deadbandDeadband value, preventing jitter near the threshold
deviationBand / rateLimitAllowed deviation range (DEVIATION) / rate-of-change upper limit (RATE_OF_CHANGE)

The alarm engine is linked to the TagEngine through TagChangeObserver: rules are evaluated automatically when a Tag value updates, with the state machine NORMAL → ACTIVE → ACKED → RETURNED. For rule management, active alarms, acknowledgement/silencing, statistics, and import/export interfaces, see the alarm engine section of the API.

The Tag aggregator supports MAX/MIN/AVG/TOTAL/DELTA/RATE sliding-window aggregation. Currently the only active routes are query interfaces (GET /api/aggregator/rules, GET /api/aggregator/rules/:id/result); no route for creating rules is registered, so a configuration entry point for rules awaits a later release.

The driver health monitor's parameters (maxConsecutiveErrors=10, watchdogTimeoutMs=30000, autoRecoverMs=60000) are set at registration time in the code, and runtime status is queried through GET /api/drivers/health; since the driver registration blocker has not been lifted, health data must be interpreted against that premise.

9. Secrets and Configuration Security Checklist ​

  • .secret.key and ciphertext configuration must be isolated from public documents, images, and logs, and stored according to the organization's secrets management policy.
  • A complete MQTT change should edit the real configuration file and restart the process, rather than relying on the "save and reconnect" wording of the PUT interface.
  • tls: true selects an MQTT TLS client connection, but the bundled Mosquitto listener on 8883 does not automatically get TLS configuration; the two must not be conflated.
  • On recovery, check the configuration path, key match, file owner, and write permissions together; a read-only configuration mount blocks .secret.key and API configuration writes, and the problem must not be masked by repeated restarts.

FastBee | fastbee.cn