Skip to content

[CJ188-COOLWATER-PARA] Integration Guide

Sensor Overview

[CJ188-COOLWATER-PARA] is integrated with ThinkLink through Source file does not provide it in Source file does not provide it mode. This guide documents the current deployable artifacts and their source-traceable versions.

ItemValue
Projectcj188_coolwater_para
VendorTKL
Model[CJ188-COOLWATER-PARA]
Business CodeNot applicable
Integration ModeSource file does not provide it
ProtocolSource file does not provide it

Model catalog

Search for these models in ThinkLink by name or ID.

Model typeNameid_namePlatform model ID
RPC[CJ188 GET] para 23103cj188_coolwater_get_2310392512371725045765
RPC[CJ188 SET] para 23103cj188_coolwater_set_2310392512050479108101
TemplateCJ188 COOL WATER92529888803688453
Thing Model[CJ188 COOLWATER]cj188_coolwater_2310392527788782784517
Thing Model[TKL-23103-CJ188-COOLWATER资产] 区域聚合cj188_coolwater_asset_23103119677189950959624
Parameter Thing Model[CJ188-COOLWATER-PARA]cj188_coolwater_para_2310392528875162046469

Features and Application Scope

This project covers [CJ188-COOLWATER-PARA] through Source file does not provide it. Its capability boundary, fields, and deployable models follow the current descriptor, requirements, and model sources.

Deployment and Data Acquisition

| DTU | Not applicable | | Power | Source file does not provide it | | LoRaWAN Class | Source file does not provide it | | Interface | Source file does not provide it | | Baud Rate | Not applicable |

Telemetry and Register Definitions

The source does not provide a standalone telemetry table; use the current thing models listed in the model inventory.

Parameter Definitions

No project-specific parameters are defined.

Requirements Evidence

The following key facts were extracted from the requirements source; line references support verification.

CategorySource FactSource
Protocol/DataDevice Type CJ/T 188-2004 0x10requirement/requirements.md:14
Protocol/Data> DI 90 1F 7 BCD/hexrequirement/requirements.md:18
Protocol/Data> / biz_code (23103)requirement/requirements.md:19
DeploymentDTU Power Mode Battery 10800mAhrequirement/requirements.md:29
Protocol/DataLoRaWAN Class Class A Battery: truerequirement/requirements.md:30
Protocol/Data> DTU CJ/T188 M-Bus KC22 KC22 supportsrequirement/requirements.md:33
Deployment> M-Bus / 300~9600bpsrequirement/requirements.md:34
Deployment> VCC/GND KC22requirement/requirements.md:36
Protocol/Data> JQ-23103-CJ188-coolwater/descriptor.yaml dtu_model: "KC22" , interface: "M-Bus"requirement/requirements.md:42
Protocol/Data> / KC22/M-Busrequirement/requirements.md:43
Deployment- 3 CJ188 — CJ/T188requirement/requirements.md:55
Protocol/Data- CJ/T188requirement/requirements.md:62
Protocol/Data- supports / supportsrequirement/requirements.md:64
Protocol/Data- CJ/T188requirement/requirements.md:65
DeploymentVoltage KC22 M-Bus / manual (input/)requirement/requirements.md:79
DeploymentPower Consumption 10800mAh manual (input/)requirement/requirements.md:80
DeploymentPower-on to Stable Working 1s 1requirement/requirements.md:86
Protocol/DataInterface Type M-Busrequirement/requirements.md:92
Protocol/DataBaud Rate 2400 bpsrequirement/requirements.md:93
DeploymentKC22 M-Bus VCC/GNDrequirement/requirements.md:102
DeploymentM-Bus+ + KC22 M-Busrequirement/requirements.md:108
DeploymentM-Bus- + KC22 M-Busrequirement/requirements.md:109
DeploymentDTU-specific wiring notes:requirement/requirements.md:111
Deployment- KC22 M-Bus VCC/GND M-Busrequirement/requirements.md:113

Thing Model and RPC Code

RPC: [CJ188 GET] para 23103

id_name: cj188_coolwater_get_23103 · ID: 92512371725045765

javascript
import {RPCHelper, Utils} from '#tklHelper';

function rpc_script({ device, params, alarms, logger, org_params }) {
let paraDef= {
        app_34: {name: "retries", field_name: "retries", unit: "",  type: "uint8"},
        app_38: { name: "pwron_delay", field_name: "pwron_delay", unit: "ms", index: 38, type: "uint16le" },
        app_70: {name: "period", field_name: "period", unit: "m",  type: "uint32LE"},
        app_150: {name: "addr", field_name: "addr", unit: "", type: "hexLE7"},
    }
    let frames=RPCHelper.buildFrame({
        paraDef:paraDef,
        params:params});
    let msg=RPCHelper.makeMSG({
        msgType:Utils.msgType.paras,
        device:device,
        dnBuffer:frames.readBuffer,
        sleepTime:0,
    })
    return [msg]
}
rpc_script({
    device: { server_attrs: {}, shared_attrs: {} },
    params: {},
    alarms: [],
    logger: console,
    org_params: {}
})

RPC: [CJ188 SET] para 23103

id_name: cj188_coolwater_set_23103 · ID: 92512050479108101

javascript
import {RPCHelper, Utils} from '#tklHelper';
import {Buffer} from "buffer";

function rpc_script({ device, params, alarms, logger, org_params }) {
let classMode = (device && device.shared_attrs && device.shared_attrs.class_mode) || "ClassA";
    const rpcName="cj188_coolwater_set_23103"
    let paraDef= {
        app_34: {name: "retries", field_name: "retries", unit: "",  type: "uint8"},
        app_38: { name: "pwron_delay", field_name: "pwron_delay", unit: "ms", index: 38, type: "uint16le" },
        app_70: {name: "period", field_name: "period", unit: "m",  type: "uint32LE"},
        app_150: {name: "addr", field_name: "addr", unit: "", type: "hexLE7"},
    }
    logger.info("set paras")
    let paraInput = {...params}
    paraInput.retries=2
    paraInput.pwron_delay=1000
    paraInput.period=params.period*60
    let frames=RPCHelper.buildFrame({
        paraDef:paraDef,
        params:paraInput});
    let redoBuffer=RPCHelper.redo()
    let dnBuffer=Buffer.alloc(frames.writeBuffer.length+frames.readBuffer.length);
    frames.writeBuffer.copy(dnBuffer,0)
    frames.readBuffer.copy(dnBuffer,frames.writeBuffer.length)
    let msgQue=Utils.makeParaSetMSG({
        device:device,
        classMode:classMode,
        rpcName:rpcName,
        params:params,
        paraDownBuffer:dnBuffer,
        extraAppBuffer:redoBuffer
    })
    if (msgQue.length==0)  return null
    return msgQue
}
rpc_script({
    device: { server_attrs: {}, shared_attrs: {} },
    params: {},
    alarms: [],
    logger: console,
    org_params: {}
})

Thing Model: [CJ188 COOLWATER]

id_name: cj188_coolwater_23103 · ID: 92527788782784517

javascript
import {PayloadParser, RPCHelper} from '#tklHelper';

function payload_parser(device, msg, thingModelId, noticeAttrs, org_params) {
let frameInfo = {
        port:22,
        dataLen:-1,
        rssi:true,
        battery:4,
        tagList:[
            { index:0, tag:0x87 },
            { index:1, tag:0x03 }
        ]
    }
    let appInfo = [
        { name:"addr", field_name:"addr", unit:"", index:5, type:"hexLE7" },
        { name:"instantflow", field_name:"instantflow", unit:"m³", index:12, type:"bcdLE4", coefficient:0.01,decimal:2 },
        { name:"totalflow", field_name:"totalflow", unit:"m³", index:17, type:"bcdLE4", coefficient:0.01,decimal:2 },
        { name:"status", field_name:"status", unit:"", index:22, type:"uint8" }
    ]
    let tdata={}
    let payParser=new PayloadParser({
        device:device,
        msg:msg,
        frameInfo:frameInfo,
        appInfo:appInfo,
    })
    tdata= payParser.telemetry()
    if((tdata?.status&0x02)===0x02) { // time out , just update the status.
        const status=tdata.status
        tdata={ ...(device.telemetry_data?.[thingModelId] ?? {})}
        tdata.status=status
    }
    let result = {
        telemetry_data: tdata,
        server_attrs: null,
        shared_attrs: null
    };
    // ── rpcHook (设备对接通用规则) ──
    if (typeof RPCHelper.buildRpcHookAction === "function") {
      const __a = RPCHelper.buildRpcHookAction({ device, msg, thingModelId, idName: "cj188_coolwater_23103", name: "[CJ188 COOLWATER]", parsed: { telemetry_data: result.telemetry_data, server_attrs: result.server_attrs, shared_attrs: result.shared_attrs } });
      if (__a) { result.actions = result.actions || []; result.actions.push(__a); }
    }
    return result;
}
console.log(payload_parser(
    { telemetry_data: {} },
    { userdata: { port: 11, payload: "" } },
    "1",
    { telemetry_data: true },
    {}
))

Thing Model: cj188_coolwater_asset_23103

id_name: cj188_coolwater_asset_23103 · ID: 119677189950959624

javascript
import {PayloadParser, RPCHelper} from '#tklHelper';

// 资产(VIRTUAL)聚合物模型 — 通用 agg_spec 驱动聚合器,见 docs/references/workflow/asset-aggregation-model.md
// device=资产, msg=源设备快照, thingModelId=本物模型ID, noticeAttrs=变更标记。
// 聚合规格在资产 server_attrs.agg_spec:min_snr=取最小(snr);min_rssi=取最小(rssi);min_battery=取最小(battery);zone_totalflow_sum=谨慎累加(totalflow);zone_instantflow_sum=谨慎累加(instantflow);online_count=在线数(—)
function payload_parser(device, msg, thingModelId, noticeAttrs) {
    if (!noticeAttrs || !noticeAttrs.telemetry_data) {
        return { telemetry_data: null, server_attrs: null, shared_attrs: null };
    }
    const sa      = device?.server_attrs || {};
    const spec    = sa.agg_spec || {};
    const members = { ...(sa.members || {}) };
    const staleMs = sa.stale_ms != null ? sa.stale_ms : 600000;
    const now     = (typeof Date !== "undefined" && Date.now) ? Date.now() : null;

    // 合并源设备各物模型的最新快照为一个扁平对象
    const srcTd = {};
    const all = msg?.telemetry_data || {};
    for (const k in all) { Object.assign(srcTd, all[k]); }

    // 收集 spec 引用到的全部源字段,把本帧带到的值并进该成员快照
    const want = {};
    for (const out in spec) { if (spec[out].src) want[spec[out].src] = true; }
    const got = {}; let touched = false;
    for (const f in want) { if (srcTd[f] !== undefined && srcTd[f] !== null) { got[f] = srcTd[f]; touched = true; } }
    if (touched && msg && msg.eui) {
        const prev = (members[msg.eui] && members[msg.eui].v) || {};
        const seq  = (members[msg.eui] && members[msg.eui].ts) || 0;
        members[msg.eui] = { v: Object.assign({}, prev, got), ts: now != null ? now : seq + 1 };
    }

    const euis = Object.keys(members);
    const fresh = euis.filter(function (e) {
        if (now == null || staleMs <= 0) return true;
        const ts = members[e].ts;
        return ts != null && ts <= now && (now - ts) <= staleMs;
    });
    const num = function (x) { return (x != null && !isNaN(x)) ? Number(x) : null; };

    const out = {};
    for (const field in spec) {
        const op = spec[field].op, src = spec[field].src;
        if (op === "count_online") { out[field] = fresh.length; continue; }
        const pool = (op === "sum_cumul") ? euis : fresh;
        const vals = pool.map(function (e) { return num(members[e].v && members[e].v[src]); }).filter(function (x) { return x != null; });
        if (op === "avg")        out[field] = vals.length ? Number((vals.reduce(function (a, b) { return a + b; }, 0) / vals.length).toFixed(2)) : null;
        else if (op === "sum_snap" || op === "sum_cumul") out[field] = vals.length ? Number(vals.reduce(function (a, b) { return a + b; }, 0).toFixed(3)) : null;
        else if (op === "max")   out[field] = vals.length ? Math.max.apply(null, vals) : null;
        else if (op === "min")   out[field] = vals.length ? Math.min.apply(null, vals) : null;
        else if (op === "or")    out[field] = pool.some(function (e) { const x = members[e].v && members[e].v[src]; return x != null && x != 0; }) ? 1 : 0;
        else if (op === "count_on") out[field] = pool.filter(function (e) { const x = members[e].v && members[e].v[src]; return x != null && x != 0; }).length;
        else out[field] = null;
    }
    let result = { telemetry_data: out, server_attrs: { members: members }, shared_attrs: null };
    // ── rpcHook (设备对接通用规则) ──
    if (typeof RPCHelper.buildRpcHookAction === "function") {
      const __a = RPCHelper.buildRpcHookAction({ device, msg, thingModelId, idName: "cj188_coolwater_asset_23103", name: "[TKL-23103-CJ188-COOLWATER资产] 区域聚合", parsed: { telemetry_data: result.telemetry_data, server_attrs: result.server_attrs, shared_attrs: result.shared_attrs } });
      if (__a) { result.actions = result.actions || []; result.actions.push(__a); }
    }
    return result;
}

// --- local debug ---(两台成员先后上报;平台会把返回的 members 持久化回 device,这里手动模拟)
const agg_spec = {
  "min_snr": {
    "op": "min",
    "src": "snr"
  },
  "min_rssi": {
    "op": "min",
    "src": "rssi"
  },
  "min_battery": {
    "op": "min",
    "src": "battery"
  },
  "zone_totalflow_sum": {
    "op": "sum_cumul",
    "src": "totalflow"
  },
  "zone_instantflow_sum": {
    "op": "sum_cumul",
    "src": "instantflow"
  },
  "online_count": {
    "op": "count_online",
    "src": ""
  }
};
const device = { name: "TKL-23103-CJ188-COOLWATER资产-1", server_attrs: { agg_spec, stale_ms: 1800000, members: {} } };
const r1 = payload_parser(device, { eui: "MEMBER_A", telemetry_data: { m1: {"snr":1,"rssi":1,"battery":1,"totalflow":1,"instantflow":1} } }, "tmid", { telemetry_data: true });
device.server_attrs.members = r1.server_attrs.members;            // 平台持久化
console.log("成员A上报后:", JSON.stringify(r1.telemetry_data));
const r2 = payload_parser(device, { eui: "MEMBER_B", telemetry_data: { m1: {"snr":2,"rssi":2,"battery":2,"totalflow":2,"instantflow":2} } }, "tmid", { telemetry_data: true });
device.server_attrs.members = r2.server_attrs.members;
console.log("成员B上报后(2台聚合):", JSON.stringify(r2.telemetry_data));
void PayloadParser;

Parameter Thing Model: [CJ188-COOLWATER-PARA]

id_name: cj188_coolwater_para_23103 · ID: 92528875162046469

javascript
import {PayloadParser, RPCHelper, Utils} from '#tklHelper';

function payload_parser(device, msg, thingModelId, noticeAttrs, org_params) {
let    port=msg?.userdata?.port || null;
    const rpcName="cj188_coolwater_set_23103"
    let paraDef= {
        app_34: {name: "retries", field_name: "retries", unit: "",  type: "uint8"},
        app_38: { name: "pwron_delay", field_name: "pwron_delay", unit: "ms", index: 38, type: "uint16le" },
        app_70: {name: "period", field_name: "period", unit: "m",  type: "uint32LE"},
        app_150: {name: "addr", field_name: "addr", unit: "", type: "hexLE7"},
    }
    if (port!==214) {
        let checkData=Utils.paraCheck(rpcName,device.server_attrs,device.shared_attrs)
        return {
            server_attrs: checkData.sdata,
            actions:checkData.actions,
        }
    }
    let pdata=(new PayloadParser({
        device:device,
        msg:msg,
        paraInfo:paraDef,
    })).paras()
    if(pdata?.period!=undefined){ pdata.period=pdata.period/60}
    let checkData= Utils.paraCheck(rpcName,device.server_attrs,pdata)
    let result = {
        telemetry_data: pdata,
        server_attrs: checkData.sdata,
        shared_attrs: pdata,
        actions: checkData.actions,
    };
    // ── rpcHook (设备对接通用规则) ──
    if (typeof RPCHelper.buildRpcHookAction === "function") {
      const __a = RPCHelper.buildRpcHookAction({ device, msg, thingModelId, idName: "cj188_coolwater_para_23103", name: "[CJ188-COOLWATER-PARA]", parsed: { telemetry_data: result.telemetry_data, server_attrs: result.server_attrs, shared_attrs: result.shared_attrs } });
      if (__a) { result.actions = result.actions || []; result.actions.push(__a); }
    }
    return result;
}
console.log(payload_parser(
    { telemetry_data: {} },
    { userdata: { port: 11, payload: "" } },
    "1",
    { telemetry_data: true },
    {}
))

Thing Model Field Definitions

Thing ModelFieldTypeUnitName
cj188_coolwater_23103snrnumberdBSNR
cj188_coolwater_23103addrnumberhexDevice Address
cj188_coolwater_23103rssinumberdBmRSSI
cj188_coolwater_23103statusnumberStatus
cj188_coolwater_23103batterynumbervBattery
cj188_coolwater_23103totalflownumberTotal Flow
cj188_coolwater_23103instantflownumberInstantaneous Flow
cj188_coolwater_asset_23103min_snrnumberdBZone SNR
cj188_coolwater_asset_23103min_rssinumberdBmZone RSSI
cj188_coolwater_asset_23103min_batterynumbervZone Battery
cj188_coolwater_asset_23103zone_totalflow_sumnumberZone Total Flow
cj188_coolwater_asset_23103zone_instantflow_sumnumberZone Instantaneous Flow
cj188_coolwater_asset_23103online_countnumberZone Online Count
cj188_coolwater_para_23103addrstringhexDevice Address
cj188_coolwater_para_23103periodnumberminPeriod
cj188_coolwater_para_23103pwron_delaynumbermsPower-on Delay

RPC Parameter Definitions

RPCParameterTypeDescriptionDefaultUnit
cj188_coolwater_set_23103addrstringModbus Addresshex
cj188_coolwater_set_23103periodnumberUpload/Collect Periodmin

Trigger Definitions

No project-specific triggers are defined.

Third-Party Platform Subscription

MQTT Topic: /v32/{Organization Account}/tkl/up/telemetry/{eui}

json
{
  "eui": "6353012af10a9331",
  "active_time": "2026-07-13T08:35:48.000Z",
  "thingModelId": "Use the platform model ID from the model inventory",
  "thingModelIdName": "Use the current telemetry model id_name",
  "telemetry_data": {
    "snr": 13.5,
    "rssi": -51,
    "battery": 3.37
  }
}

Template Selection and Verification

Search ThinkLink by project name, business code, or the id_name and ID values in the model inventory. After deployment, use real uplinks to verify fields, units, RPCs, and trigger behavior.

Supplementary Notes

Requirements and decisions: requirement/requirements.md.