---
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;
}
```