--- tags: 'Acer' --- Smart Meter Reader Protocol ( Taipei Water ) === ## Data Encode <font color=red>!!! Important: For image data, we don't need to encode. if the bytes number of data is odd, please add one more byte after the data, let it become "EVEN" bytes. </font> 1. Random data(2 bytes) + data + CRC(2 bytes) 2. Reverse high & low bytes position before last two bytes(CRC) ### Encode Example: ``` Data: 1,2,3,4 Random Seed: 88 72 Encode with Seed : 88,72,89,74,91,76 Add Payload CRC : 88,72,89,74,91,76,228,130 Reverse High/Low Bytes before CRC : 72,88,74,89,76,91,228,130 ``` ### Decode Example ``` Got payload: 72,88,74,89,76,91,228,130 Reverse Paylod: 88,72,89,74,91,76,228,130 Check CRC, then get data + data CRC : 88,72,89,74,91,76 Decode by xor operation with random seed: 1,2,3,4 ``` ### NodeJS Code ``` let primer = new (require("./Primer/Primer.js"))(); let data = new Array(1, 2, 3, 4); console.log("Encode Example:"); console.log("Data: ", data.toString()); let d0 = parseInt(Math.random() * 256); let d1 = parseInt(Math.random() * 256); console.log("Random Seed:", d0, d1); let output = new Array(); output.push(d0); output.push(d1); for (let i = 0; i < data.length; i += 2) { output.push(d0 ^ data[i]); output.push(d1 ^ data[i + 1]); } console.log("Encode with Seed : ", output.toString()); primer.makeCRC16(output); console.log("Add Payload CRC : ", output.toString()); for (let i = 0; i < output.length - 2; i += 2) { let tmp = output[i]; output[i] = output[i + 1]; output[i + 1] = tmp; } console.log("Reverse High/Low Bytes before CRC : ", output.toString()); console.log("\r\nDecode Example:"); console.log("Got payload: ", output.toString()); for (let i = 0; i < output.length - 2; i += 2) { let tmp = output[i]; output[i] = output[i + 1]; output[i + 1] = tmp; } console.log("Reverse Paylod: ", output.toString()); output.pop(); output.pop(); console.log("Check CRC, then get data + data CRC : ", output.toString()); let payload = new Array(); for (let i = 2; i < output.length; i += 2) { payload.push(output[0] ^ output[i]); payload.push(output[1] ^ output[i + 1]); } console.log("Decode by xor operation with random seed: ", payload.toString()); ``` ## Water Meter ### Protocol #### Register ##### Request "Protocol Version 0" ```json= { UINT8 commandCode; // Always be 0x01 UINT8 MeterNumber[16]; UINT8 IMEI[16]; UINT8 IMSI[16]; INT16 RSRP; INT16 RSRQ; INT16 Battery; // (value*100) UINT32 MeterType; UINT8 protocolVersion; // Always be 0 UINT16 CRC; } STC_REGISTER; ``` ##### Response "Protocol Version 0" ```json= { UINT8 commandCode; // Always be 0x02 UINT8 MeterNumber[16]; UINT8 IMEI[16]; UINT8 IMSI[16]; UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 samplingTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uplinkTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uploadServerIP[16]; UINT16 uploadServerPort; UINT8 imageServerIP[16]; UINT16 imageServerPort; UINT32 samplingPeriod; UINT32 uplinkPeriod; UINT32 MeterType; UINT16 command; UINT8 imageDate[6]; UINT8 reserved; UINT16 CRC; } STC_REGISTER_RESPONSE; ``` ##### Request "Protocol Version 1" <font color='red'>2020/05/29 新增 Battery 變數,伺服器變更</font> ```json= { UINT8 commandCode; // Always be 0x01 UINT8 MeterNumber[16]; UINT8 IMEI[16]; UINT8 IMSI[16]; INT16 RSRP; INT16 RSRQ; INT16 Battery; // (value*100) UINT32 MeterType; UINT8 protocolVersion; // Always be 1 UINT8 v0; UINT8 v1; UINT8 v2; UINT8 reserved; // for odd bytes UINT16 CRC; } STC_REGISTER; ``` ##### Response "Protocol Version 1" Same as Response "Protocol Verison 0" <font color='red'>Request "Protocol Version 2"</font> ```json= { UINT8 commandCode; // Always be 0x01 UINT8 MeterNumber[16]; UINT8 IMEI[16]; UINT8 IMSI[16]; INT16 RSRP; INT16 RSRQ; INT16 Battery; // (value*100) UINT32 MeterType; UINT8 protocolVersion; // Always be 2 UINT8 v0; UINT8 v1; UINT8 v2; UINT8 reserved; UINT16 CRC; } STC_REGISTER; ``` <font color='red'>Response "Protocol Version 2"</font> ```json= { UINT8 commandCode; // Always be 0x02 UINT8 MeterNumber[16]; UINT8 IMEI[16]; UINT8 IMSI[16]; UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 samplingTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uplinkTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uploadServerIP[16]; UINT16 uploadServerPort; UINT8 imageServerIP[16]; UINT16 imageServerPort; UINT32 samplingPeriod; UINT32 uplinkPeriod; UINT32 MeterType; UINT16 command; UINT8 imageDate[6]; UINT8 secondDataServerIP[16]; // if disable, secondServerIP[0] equal 0 UINT16 secondDataServerPort; // if disable, secondServerPort equal 0 UINT8 secondImageServerIP[16]; // if disable, secondServerIP[0] equal 0 UINT16 secondImageServerPort; // if disable, secondServerPort equal 0 UINT8 reserved; UINT16 CRC; } STC_REGISTER_RESPONSE; ``` #### Commands: |Code|Name| |---|---| |0x00|None| |0x01|uploadImage| |0x02|uploadROI| |0x03|setParameters| <B>Meter will send "request parameters" if it received command code == 0x03</B> ##### Request Parameters ```json= { UINT8 commandCode; // Always be 0x0b UINT8 MeterNumber[16]; UINT16 requestVersion; UINT8 reserved; UINT16 CRC; } STC_REGISTER_RESPONSE; ``` ##### Response for "requestVersion=0" ```json= { UINT8 commandCode; // Always be 0x0C UINT8 MeterNumber[16]; UINT16 requestVersion; // Always be 0x0000 UINT8 newMeterNumber[16]; // if no change,newMeterNumber[0] equal 0 UINT8 newRegisterIP[16]; // if no change,newRegisterIP[0] equal 0 UINT16 newRegisterPort; // if no change,newRegisterPort equal 0 FLOAT64 refferenceVolume; // if no change,refferenceValue equal -1 UINT8 digitalNumbers; // if digitalNumbers equal 0, means no change UINT32 MeterType; UINT8 IntegerNo; UINT8 DecimalNo; INT16 ROI_Angle; // if no chagne, digitalNumbers equal 0 INT32 Max_Flow; // if no change, fill -1 UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; .... UINT16 command; UINT8 imageDate[6]; UINT16 CRC; } STC_REGISTER_RESPONSE; ``` Response of "requestVersion=0" for GT: ``` { UINT8 commandCode; // Always be 0x0C UINT8 MeterNumber[16]; UINT16 requestVersion; // Always be 0x0000 UINT8 newMeterNumber[16]; // if no change,newMeterNumber[0] equal 0 UINT8 newRegisterIP[16]; // if no change,newRegisterIP[0] equal 0 UINT16 newRegisterPort; // if no change,newRegisterPort equal 0 FLOAT64 refferenceVolume; (-1) UINT8 digitalNumbers; (0) UINT32 MeterType; (0) UINT8 IntegerNo; (0) UINT8 DecimalNo; (0) INT16 ROI_Angle; (0) // if no chagne, digitalNumbers equal 0 INT32 Max_Flow; (-1) // if no change,fill -1 UINT16 command; UINT8 imageDate[6]; UINT16 CRC; } STC_REGISTER_RESPONSE; ``` ##### Response for "requestVersion=1" ```json= { UINT8 commandCode; // Always be 0x0C UINT8 MeterNumber[16]; UINT16 requestVersion; // Always be 0x0000 UINT8 newMeterNumber[16]; // if no change,newMeterNumber[0] equal 0 UINT8 newRegisterIP[16]; // if no change,newRegisterIP[0] equal 0 UINT16 newRegisterPort; // if no change,newRegisterPort equal 0 FLOAT64 refferenceVolume; // if no change,refferenceValue equal -1 UINT8 digitalNumbers; // if digitalNumbers equal 0, means no change UINT32 MeterType; UINT8 IntegerNo; UINT8 DecimalNo; INT16 ROI_Angle; // if no chagne, digitalNumbers equal 0 INT32 Max_Flow; // if no change, fill -1 UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; .... UINT16 command; UINT8 imageDate[6]; UINT8 secondDataServerIP[16]; // if disable, secondServerIP[0] equal 0 UINT16 secondDataServerPort; // if disable, secondServerPort equal 0 UINT8 secondImageServerIP[16]; // if disable, secondServerIP[0] equal 0 UINT16 secondImageServerPort; // if disable, secondServerPort equal 0 INT16 imageShift_y; // if no change, equal -1 UINT16 CRC; } STC_REGISTER_RESPONSE; ``` Response of "requestVersion=1" for GT: ``` { UINT8 commandCode; // Always be 0x0C UINT8 MeterNumber[16]; UINT16 requestVersion; // Always be 0x0000 UINT8 newMeterNumber[16]; // if no change,newMeterNumber[0] equal 0 UINT8 newRegisterIP[16]; // if no change,newRegisterIP[0] equal 0 UINT16 newRegisterPort; // if no change,newRegisterPort equal 0 FLOAT64 refferenceVolume; (-1) UINT8 digitalNumbers; (0) UINT32 MeterType; (0) UINT8 IntegerNo; (0) UINT8 DecimalNo; (0) INT16 ROI_Angle; (0) // if no chagne, digitalNumbers equal 0 INT32 Max_Flow; (-1) // if no change,fill -1 UINT16 command; UINT8 imageDate[6]; UINT8 secondDataServerIP[16]; // if disable, secondServerIP[0] equal 0 UINT16 secondDataServerPort; // if disable, secondServerPort equal 0 UINT8 secondImageServerIP[16]; // if disable, secondServerIP[0] equal 0 UINT16 secondImageServerPort; // if disable, secondServerPort equal 0 INT16 imageShift_y; (-1) // no change UINT16 CRC; } STC_REGISTER_RESPONSE; ``` ### Data Collector ##### Data Upload ###### Request ```json= { UINT8 commandCode; // Always be 0x03 UINT8 MeterNumber[16], UINT8 uploadRecords; INT16 RSRP; INT16 RSRQ; INT16 Battery; ( Value*100 ) FLOAT64 Volume; UINT8 recordTime[6]; // ( YYMMDDHHMMSS in binary ) FLOAT64 Volume; UINT8 recordTime; ... UINT16 CRC; } STC_DATA_REPORT; ``` ###### Response ```json= { UINT8 commandCode; // Always be 0x04 UINT8 MeterNumber[16]; UINT8 uploadRecords; UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 samplingTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 uplinkTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 uploadServerIP[16]; UINT16 uploadServerPort; UINT8 imageServerIP[16]; UINT16 imageServerPort; UINT32 samplingPeriod; UINT32 uplinkPeriod; UINT32 MeterType; UINT16 command; // Mask 0x01: upload image , 0x02: upload ROI UINT8 imageDate[6]; UINT16 CRC; } STC_DATA_REPORT_RESPONSE; ``` ##### Alert Upload AlertType: * 0x01: No Battery * <font color='color'> 0x02: Battery package communication error</font> ###### Request ```json= { UINT8 commandCode; // Always be 0x05 UINT8 MeterNumber[16]; UINT8 alertType; FLOAT64 Volume; INT16 Battery; // ( Value*100 ) INT16 RSRP; INT16 RSRQ; UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary ) UINT16 CRC; } ``` ###### Response ```json= { UINT8 commandCode; // Always be 0x06 UINT8 alertType; UINT8 MeterNumber[16]; UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 samplingTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 uplinkTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 uploadServerIP[16]; UINT16 uploadServerPort; UINT8 imageServerIP[16]; UINT16 imageServerPort; UINT32 samplingPeriod; UINT32 uplinkPeriod; UINT32 MeterType; UINT16 command; // Mask 0x01: upload image , 0x02: upload ROI UINT8 imageDate[6]; UINT16 CRC; } ``` ### Image Collector #### UDP API: Upload Image ###### Request ```json= { UINT8 commandCode; // Always be 0x07 UINT8 MeterNumber[16]; UINT8 captureTime[6]; // ( YYMMDDHHMMSS in binary ) UINT16 width; UINT16 height; UINT32 totalSize; UINT16 totalBatchNum; UINT16 batchIndex; UINT8 imageType; // 0: B&W 1: Gray 2: compressed B&W 3: compressed Gray UINT8 data[dataSize]; // dataSize=totalSize/totalBatchNum. UINT16 CRC; } ``` ###### Response ```json= { UINT8 commandCode; // Always be 0x08 UINT8 MeterNumber[16]; UINT8 captureTime[6]; // ( YYMMDDHHMMSS in binary ) UINT16 width; UINT16 height; UINT32 totalSize; UINT16 totalBatchNum; UINT16 batchIndex; UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary ) UINT8 imageType; // 0: B&W 1: Gray 2: compressed B&W 3: compressed Gray UINT16 command; // Mask 0x01: upload image , 0x02: upload ROI UINT8 imageDate[6]; UINT16 CRC; } ``` #### UDP API: Upload ROI ###### Request Version 0 ```json= { UINT8 commandCode; // Always be 0x09 UINT8 MeterNumber[16]; UINT8 protocolVersion; // Always be 0 UINT8 reserved; UINT8 digitalNumbers; UINT32 MeterType; UINT8 IntegerNo; UINT8 DecimalNo; INT16 imageShift_y; UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; .... UINT16 CRC; } ``` ###### Response Version 0 ```json= { UINT8 commandCode; // Always be 0x0A UINT8 MeterNumber[16]; UINT8 digitalNumbers; UINT32 MeterType; UINT8 IntegerNo; UINT8 DecimalNo; UINT16 command; // Mask 0x01: upload image , 0x02: upload ROI UINT8 imageDate[6]; UINT16 CRC; } ``` ###### Request Version 1 ```json= { UINT8 commandCode; // Always be 0x09 UINT8 MeterNumber[16]; UINT8 protocolVersion; // Always be 0x01 UINT8 reserved; UINT8 digitalNumbers; UINT32 MeterType; UINT8 IntegerNo; UINT8 DecimalNo; INT16 ROI_Angle; INT32 Max_Flow; INT16 imageShift_y; UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; UINT16 xLeftTop; UINT16 yLeftTop; UINT16 xRightTop; UINT16 yRightTop; UINT16 xLeftBottom; UINT16 yLeftBottom; UINT16 xRightBottom; UINT16 yRightBottom; UINT8 OCRParameters; UINT8 FontWidth; UINT8 FontId; UINT8 RoID; .... UINT16 CRC; } ``` ###### Response Version 1 ```json= { UINT8 commandCode; // Always be 0x0A UINT8 MeterNumber[16]; UINT8 digitalNumbers; UINT32 MeterType; UINT8 IntegerNo; UINT8 DecimalNo; UINT16 command; // Mask 0x01: upload image , 0x02: upload ROI UINT8 imageDate[6]; UINT16 CRC; } ``` ### IDAM Register ##### Get Device List ```json= { UINT8 commandCode; // Always be 0x10 UINT8 MeterNumber[16]; UINT8 IMEI[16]; UINT8 IMSI[16]; INT16 RSRP; INT16 RSRQ; INT16 Battery; // (value*100) UINT32 MeterType; UINT8 protocolVersion; // Always be 0 or 1 UINT8 v0; UINT8 v1; UINT8 v2; UINT8 startIndex; // for odd bytes UINT16 CRC; } ``` ###### Response for protocol version 0 ```json= { UINT8 commandCode; // Always be 0x11 UINT8 MeterNumber[16]; // UUID for IDAM UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 samplingTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uplinkTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uploadServerIP[16]; UINT16 uploadServerPort; UINT8 imageServerIP[16]; UINT16 imageServerPort; UINT32 samplingPeriod; UINT32 uplinkPeriod; UINT16 command; UINT8 imageDate[6]; UINT32 p2pUploadOffset; // P2P upload offset UINT8 p2pTimeSliceUnit; UINT8 neverSleep; UINT16 imageTimeSlice; UINT16 earlyWakeUp; UINT8 totalP2pDevices; UINT8 startIndex; UINT8 batchDeviceNum; UINT8 MeterNumber1[16]; UINT8 MeterNumber2[16]; ... ... ... // According to meter numbers, 20 devices max for each batch UINT16 CRC; } ``` ###### Response for protocol version 1 ```json= { UINT8 commandCode; // Always be 0x11 UINT8 MeterNumber[16]; // UUID for IDAM UINT8 currentTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 samplingTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uplinkTime[6]; // ( YYMMDDHHMMSS in binary) UINT8 uploadServerIP[16]; UINT16 uploadServerPort; UINT8 imageServerIP[16]; UINT16 imageServerPort; UINT32 samplingPeriod; UINT32 uplinkPeriod; UINT16 command; UINT8 imageDate[6]; UINT32 p2pUploadOffset; // P2P upload offset UINT8 p2pTimeSliceUnit; UINT8 neverSleep; UINT16 imageTimeSlice; UINT16 earlyWakeUp; UINT8 totalP2pDevices; UINT8 offsetP2PID; // new in Version 1 UINT8 reserved; // new in version 1 UINT8 startIndex; UINT8 batchDeviceNum; UINT8 MeterNumber1[16]; UINT8 MeterNumber2[16]; ... ... ... // According to meter numbers, 20 devices max for each batch UINT16 CRC; } ``` ##### upload Device Status ```json= { UINT8 commandCode; // Always be 0x12 UINT8 MeterNumber[16]; INT16 RSRP; INT16 RSRQ; INT16 Battery; // (value*100) UINT8 protocolVersion; // Always be 0 UINT8 neverSleep; UINT8 time[6]; UINT8 state; UINT8 reserved; UINT8 deviceNum; UINT16 deviceJoinStatus[20]; UINT16 CRC; } ``` ###### Response ```json= { UINT8 commandCode; // Always be 0x13 UINT8 neverSleep; UINT8 forceSleep; UINT8 reboot; UINT16 CRC; } ```