Skip to content

Custom TC4: Agent JSON reference ​

Use this contract to generate a HiBean import file from real device evidence. See the human guide for preparation, import, and device verification.

Source baseline: 2026-10-19, App 1.5.4+189, commit d12c9d07bc61e9d2e908f9e718bfd78301b6e3f6. This identifies the inspected source, not availability to every user. File profileVersion: 1 and schemaVersion: 2 are independent of the App version.

Agent workflow and deliverables ​

  1. Obtain device model, firmware version, user platform, and transport. Start with firmware source, manufacturer protocol, actual GATT services and characteristics, serial settings, and raw transmitted/received data. Do not infer a protocol from a product name or another device's profile.
  2. Confirm the read command, outgoing terminator, response terminator, a complete raw response, and each field's meaning and unit. Temperatures must be Celsius: custom devices interpret temperatures as Celsius and JSON provides no conversion.
  3. For device controls, also confirm command templates, limits, steps, safe values, and corresponding state readback. A safe value depends on the equipment and operating conditions; zero is not universally safe.
  4. If required facts are missing, ask focused questions or request the specific raw evidence. Do not label guessed profiles ready to use. Use actuators: {} for monitoring when that meets the user's goal; do not silently remove requested controls.
  5. Generate a UTF-8 .json file no larger than 1 MiB, using only the keys below. No comments, trailing commas, or Markdown fences in the file. Do not present placeholder endpoints as completed configurations.
  6. Outside the JSON, provide parameter sources, unresolved facts, verification status, and human next steps. Import must still be followed by connection, consecutive reads, control verification if enabled, manual recording settings, and save.

Keep three conclusions separate: codec validation passed establishes the file contract; hardware reads passed establishes connectivity and parsing; hardware control proof passed additionally requires target and safe-value readback. Import does not carry verification proofs or automatically create a device.

Envelope and config ​

Unknown keys are rejected at every object level. Required keys cannot be omitted or replaced with null.

PathType / valueRule
kindstringRequired; exactly hibean.tc4.custom.profile
profileVersionintegerRequired; exactly 1
configobjectRequired; only the seven keys below
config.schemaVersionintegerRequired; exactly 2
config.transportTypestringRequired; socket, websocket, classic_bluetooth, ble, or serial
config.transportobjectRequired; matches transport type
config.initializationCommandsstring[]Required; [] when unused; each command nonempty and without CR/LF
config.statusPollingobjectRequired; see reading contract
config.actuatorCommandSeparatorstringRequired; "\n", "\r", or "\r\n"
config.actuatorsobjectRequired; {} for no device controls

Use JSON numbers and booleans, not strings such as "1000" or "true". Prefer integer literals for integers. There are no name, id, description, platform, recordProfile, proofs, or testValue properties. A transport's endpoint identifier is distinct from the device identity assigned by the App on save.

Transport contract ​

Only the listed keys are allowed for each transport. All are required unless marked optional. Strings must be nonempty after trimming.

transportTypetransport fieldsConstraints
sockethost: string; port: integerRaw TCP; port 1–65535; host without URL scheme
websockethost: string; port: integer; websocketPath: stringPort 1–65535; path starts with /; current implementation uses wss only for port 443, otherwise ws
classic_bluetoothidentifier: stringActual Classic Bluetooth target on the current platform
bleidentifier, serviceUuid, writeCharacteristicUuid: string; optional notifyCharacteristicUuid: stringUse actual scan/GATT evidence; omit unused optional value rather than supplying an empty string
serialportName: string; connectionParams: objectActual system port name; settings below

There are no URL, authentication header, TLS switch, BLE write mode, MTU, or chunk-size properties. BLE identifiers may be iOS UUIDs or Bluetooth addresses on other platforms; do not promise cross-platform portability. Service and characteristic UUIDs are different roles.

BLE reception depends on notification subscriptions; there is no characteristic Read fallback. An optional notifyCharacteristicUuid in JSON does not mean arbitrary devices work without a notification setup: confirm that the App can select a usable notifying characteristic. Current writing sets preferWriteWithoutResponse=false; adding invented JSON keys cannot support hardware requiring only writes without response.

Wizard platform policy: Android supports all except serial; iOS supports BLE, TCP, and WebSocket; macOS and Windows support all five; Linux is unsupported. This does not guarantee OS driver or hardware compatibility.

serial.connectionParams ​

KeyTypeConstraint
baudRateintegerRequired; positive
dataBitsintegerRequired; 5–8
stopBitsintegerRequired; 1 or 2
paritystringRequired; none, even, odd, mark, or space
flowControlstringRequired; none, xonxoff, rtscts, or dtrdsr
timeoutSecondsnumberOptional; positive and finite; a serial setting, not the status-frame timeout

Initialization, reading, and framing ​

statusPolling must contain exactly these four keys:

KeyTypeConstraint
commandstringNonempty, no CR/LF; obtained from the device protocol
intervalMillisintegerAt least 1000 milliseconds
messageSeparatorstringOnly "\n", "\r", or "\r\n"
fieldsobject[]Nonempty; each item has only signal, type, and index

Despite its name, actuatorCommandSeparator terminates all outgoing initialization, read, and control commands. Incoming data uses messageSeparator; the two may differ. JSON "\n" decodes to LF; "\\n" is a literal backslash and n and is invalid as a separator. Do not also append terminators inside commands or templates.

The connection step opens the transport and selects GATT resources as needed. Initialization commands are sent in order during status verification, before sample and baseline reads. There are no configurable initialization ACKs, delays, or automatic unit-change commands. Add commands such as UNITS;C only if supported by the actual firmware.

TCP, BLE, Classic Bluetooth, and serial wait for a complete delimiter. The current frame timeout is 5 seconds and the buffer limit is 64 Ki characters. A complete WebSocket message can serve as a frame without a trailing delimiter, but messageSeparator is still required in JSON. Parsing uses the first nonempty frame, splits on commas, and trims fields. Empty fields keep their index positions; mapping an empty field fails.

Fields and signals ​

index is a zero-based integer from 0 to 255. Neither indexes nor signals may repeat. Omit unwanted mappings while retaining original indexes. type is exactly double or integer, never int.

signalMeaningType constraints
bean_temperatureBean temperature (BT)Required mapping; normally double
environment_temperatureEnvironment temperature (ET)Normally double
inlet_temperatureInlet temperatureNormally double
heater_powerHeater readbackPrefer integer for control
fan_speedFan readbackPrefer integer for control
drum_speedDrum readbackPrefer integer for control
target_temperatureTarget temperature readbackMust be integer; no corresponding target-temperature actuator
cooling_fan_switchCooling fan readbackPrefer integer for control

There is no unknown signal; leave unmapped fields out of the array. Values must parse as finite numbers without suffixes such as °C or %. integer requires mathematically integral values (180.0 is accepted). There are no field delimiter, scale, offset, regex, formula, or temperature conversion properties. Incompatible firmware output requires a protocol change or separate adapter, not invented JSON keys.

Actuators and proof ​

Only heater, fan, drum, and coolingFan are allowed; note the camelCase spelling of the last key. Use {} for no controls and omit unused items.

Field in each actuatorTypeConstraint
enabledbooleanRequired
modestringRequired; range or toggle
commandTemplatestringRequired; when enabled, nonempty, contains exact {value}, and no CR/LF
safeValueintegerRequired; valid safe value when enabled
rangeobjectRequired in range mode; exactly integer min, max, step; omit in toggle mode

Enabled range controls require min < max, step > 0, and (max-min) % step == 0. The safe value must be in range and satisfy (safeValue-min) % step == 0. Enabled toggles use 0/1, including the safe value. Enabled coolingFan supports only toggle mode. Templates replace {value} with an integer; there is no general expression language.

Disabled items still require the correct object shape and types; a disabled range item still needs a range object with a positive integer step. Prefer omission over meaningless placeholder controls.

Enabled actuatorRequired mapped readback
heaterheater_power
fanfan_speed
drumdrum_speed
coolingFancooling_fan_switch

Control readbacks must be integral and satisfy the configured range, step, or toggle bounds, including baseline reads. Temperature change is not heater-power readback.

After three consecutive successful reads, the person chooses a valid test value different from the safe value: write test value → read matching state → write safe value → read matching safe state. The test value is not a JSON field. An explicit target mismatch triggers a safe restore attempt and then fails proof. If a write/read result is uncertain, the session is closed/invalidated without a speculative second command. Failed safe readback means safety is unconfirmed.

Manual recording settings select values a person records during roasting; they are not device controls and are not part of portable JSON. JSON also carries no automated tests, PID, or automatic cooling workflow.

Complete examples and downloads ​

These are synthetic contract examples, not verified customer profiles. Addresses, UUIDs, READ, and OT1 are not universal defaults. Replace them using real device evidence before delivering a file for a user to try importing.

Monitor bean temperature over TCP ​

Assumes the device receives READ followed by LF and returns 180.5 followed by LF, with Celsius BT in column 0 and no enabled controls.

json
{
  "kind": "hibean.tc4.custom.profile",
  "profileVersion": 1,
  "config": {
    "schemaVersion": 2,
    "transportType": "socket",
    "transport": {
      "host": "192.0.2.10",
      "port": 4000
    },
    "initializationCommands": [],
    "statusPolling": {
      "command": "READ",
      "intervalMillis": 1000,
      "messageSeparator": "\n",
      "fields": [
        {
          "signal": "bean_temperature",
          "type": "double",
          "index": 0
        }
      ]
    },
    "actuatorCommandSeparator": "\n",
    "actuators": {}
  }
}

Monitor bean temperature and control a heater over TCP ​

Also assumes a reply of 180.5,0 followed by LF; integer heater power in column 1; OT1;integer followed by LF sets power from 0–100 in steps of 1; and the manufacturer confirms zero is safe under the current operating conditions. Do not reuse this control example without all these facts.

json
{
  "kind": "hibean.tc4.custom.profile",
  "profileVersion": 1,
  "config": {
    "schemaVersion": 2,
    "transportType": "socket",
    "transport": {
      "host": "192.0.2.10",
      "port": 4000
    },
    "initializationCommands": [],
    "statusPolling": {
      "command": "READ",
      "intervalMillis": 1000,
      "messageSeparator": "\n",
      "fields": [
        {
          "signal": "bean_temperature",
          "type": "double",
          "index": 0
        },
        {
          "signal": "heater_power",
          "type": "integer",
          "index": 1
        }
      ]
    },
    "actuatorCommandSeparator": "\n",
    "actuators": {
      "heater": {
        "enabled": true,
        "mode": "range",
        "commandTemplate": "OT1;{value}",
        "safeValue": 0,
        "range": {
          "min": 0,
          "max": 100,
          "step": 1
        }
      }
    }
  }
}

The other monitoring files retain the same READ / Celsius BT / LF assumptions and change transport only. WebSocket /ws, serial 115200/8/N/1/no flow control, and BLE FFE0 service / FFE2 write / FFE1 notification are illustrative settings.

Troubleshooting and maintenance sources ​

Failure stageCheck first
ImportEnvelope, versions, unknown keys, types, duplicate indexes, required BT, control readback mappings
ConnectionPlatform support, address/port, serial permissions, Bluetooth target, service and characteristic UUIDs
Connected but no readInitialization timing, actual read command, outgoing terminator, notification subscription, reply delimiter
Data received but parse failedFirst frame being an ACK rather than status, comma positions, numeric units/scaling, integer types
Control proofCommand/readback represent the same quantity, bounds/step, device execution, target and safe readbacks

Corrections from the earlier guide: replaced an empty config illustration with a full import contract; moved initialization timing from connection to read verification; clarified fixed comma parsing and BLE notifications; explained the outgoing terminator applies to READ and initialization; added manual recording and separated import validation from hardware verification.

For maintenance, recheck these App sources rather than inferring new capabilities from examples:

  • lib/model/manufacture/tc4/custom/tc4_custom_profile.dart — Tc4CustomProfileCodec / Tc4CustomConfigJsonCodec

  • lib/model/manufacture/tc4/custom/tc4_custom_models.dart — enums / Tc4CustomConfigValidator

  • lib/model/manufacture/tc4/custom/tc4_text_protocol.dart — framing / parsing / readback

  • lib/model/manufacture/tc4/custom/tc4_custom_tester.dart — transport / initialization / writes

  • lib/model/manufacture/tc4/custom/onboarding/tc4_setup_controller.dart — platform / baseline / proof

  • lib/model/manufacture/tc4/custom/onboarding/tc4_custom_provisioner.dart — save

  • lib/page/discovery/tc4/tc4_custom_setup_v2_page.dart — workflow / manual recording

  • lib/model/manufacture/manufacture_constants.dart — default Celsius policy

  • lib/model/manufacture/tc4/custom/tc4_custom_roaster.dart — runtime state publication

  • lib/model/persistence/serial_port_enums.dart — serial enum values

  • lib/model/manufacture/tc4/custom/tc4_custom_profile_file_service.dart — UTF-8 / file size