极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 24149|回复: 23

麻瓜项目:家庭能源消耗可视化管理之“网络电能表”

[复制链接]
发表于 2013-7-2 22:00:45 | 显示全部楼层 |阅读模式
本帖最后由 muggle 于 2013-9-1 09:43 编辑

家庭能源消耗管理,是指能够即时查看电力消耗数据,而且能够通过历史数据图表,实现能源消耗的可视化管理。国外的电力公司,一般都为用户提供丰富的可视化能源管理数据,也曾经有Google和Microsoft等互联网巨头参与其中。但是,国内这方面一直还是空白,电力公司的抄表数据只是收费用途,并不能提供家庭能源消耗的数据,很多家庭的跑冒滴漏浪费因此产生。

我曾经考虑了很久,也参考了一些国外的商业和开源物联网项目。从去年中期,开始确定要做想法一个网络电能表,其间经历了许多波折,终于在六月份完成了家庭电表数据上网,真正实现了家庭能源消耗的可视化管理。

试验项目链接:
http://www.lewei50.com/home/gatewaystatus/1117

微博推送的时点和日/周/月统计信息
http://weibo.com/u/1665750791

这是早在一月份分享的一个测试版本,当时只是一个插座的数据,而且遇到了数据转换的问题,终于在朋友的帮助下,克服了困难,但是也停顿了很久。
http://www.geek-workshop.com/thread-3178-1-1.html

目前实现的项目,技术并没有什么突破,只是将分流电阻取样的电量模块,改成了以互感器取样的电量模块。物联网数据上传部分,采用485-MODBUS接口连接到Arduino,最后由5100盾板将数据传送到乐为互联。

网络电量表预计有下面三个版本:
电量模块+485+Arduino+5100                      (有线网络版本)   2013.06.30已经实现
电量模块+485+Arduino+串口WIFI                (无线网络版本)   近期计划
电量模块+485+Arduino+GPRS                      (无线网络版本)   2013.07.18原型测试成功,有待套件优化

  1. // LeWei AC Power Meter trail success2013.06.25
  2. // LeWei AC Power Meter (ZongBiao60A)trail syccess 2013.06.30 18:50pm
  3. // 4 Parameter: watt / kwh / Amp / Voltage / Pf

  4. /* FIXME: not yet being used */
  5. unsigned long interframe_delay = 2;  /* Modbus t3.5 = 2 ms */

  6. /*
  7. * preset_multiple_registers: Modbus function 16. Write the data from an
  8. * array into the holding registers of a slave.
  9. * INPUTS
  10. * slave: modbus slave id number
  11. * start_addr: address of the slave's first register (+1)
  12. * reg_count: number of consecutive registers to preset
  13. * data: array of words (ints) with the data to write into the slave
  14. * RETURNS: the number of bytes received as response on success, or
  15. *         0 if no bytes received (i.e. response timeout)
  16. *        -1 to -4 (modbus exception code)
  17. *        -5 for other errors (port error, etc.).
  18. */

  19. int preset_multiple_registers(int slave, int start_addr,
  20. int reg_count, int *data);

  21. /*
  22. * read_holding_registers: Modbus function 3. Read the holding registers
  23. * in a slave and put the data into an array
  24. * INPUTS
  25. * slave: modbus slave id number
  26. * start_addr: address of the slave's first register (+1)
  27. * count: number of consecutive registers to read
  28. * dest: array of words (ints) on which the read data is to be stored
  29. * dest_size: size of the array, which should be at least 'count'
  30. * RETURNS: the number of bytes received as response on success, or
  31. *         0 if no valid response received (i.e. response timeout, bad crc)
  32. *        -1 to -4 (modbus exception code)
  33. *        -5 for other errors (port error, etc.).
  34. */

  35. int read_holding_registers(int slave, int start_addr, int count,
  36. int *dest, int dest_size);


  37. /*
  38.    open.lewei50.com  sensor  client
  39. */



  40. #include <SPI.h>
  41. #include <Ethernet.h>
  42. #include <LeweiClient.h>

  43. #define USERKEY          "Your API Key" // replace your key here
  44. #define LW_GATEWAY       "Your Gateway No."
  45.   
  46. LeWeiClient *lwc;


  47. unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
  48. boolean lastConnected = false;                 // state of the connection last time through the main loop
  49. const unsigned long postingInterval = 30*1000; //delay between updates to cosm.com


  50. int pin = 8;
  51. unsigned long duration;
  52. unsigned long starttime;
  53. unsigned long sampletime_ms = 30000;
  54. unsigned long lowpulseoccupancy = 0;
  55. float ratio = 0;
  56. double concentration = 0;

  57. void setup() {

  58.    // start serial port:
  59.    Serial.begin(4800);
  60.    pinMode(8,INPUT);

  61.   delay(10000);               
  62.    
  63.    lwc = new LeWeiClient(USERKEY, LW_GATEWAY);

  64.    starttime = millis();
  65. }
  66. /* filter program : 20130521 */
  67. #define FILTERLEN 10

  68. unsigned long Array_Average( unsigned long* Array,int length)
  69. {
  70.     int x;
  71.     unsigned long returnVal;
  72.     unsigned long result=0;
  73.     for(x=0;x<length;x++)
  74.     {
  75.       result+=Array[x];
  76.       Serial.print("result=");
  77.       Serial.println(result);
  78.     }
  79.     returnVal=result/length;
  80.     return returnVal;
  81. }

  82. unsigned long Filter1(unsigned long lowpulse)
  83. {
  84.   static unsigned long sfiterArray[FILTERLEN];
  85.   static int sindex=0;
  86.   int x;
  87.    Serial.println("filter1 begin:");
  88.   if(FILTERLEN>sindex)
  89.   {
  90.       sindex++;
  91.       Serial.println(sindex);
  92.       sfiterArray[sindex]=lowpulse;
  93.          Serial.println("filter1 END");
  94.       return lowpulse;
  95.   }
  96.   else
  97.   {
  98.       for(x=0;x<FILTERLEN-1;x++)
  99.       {
  100.         sfiterArray[x]=sfiterArray[x+1];
  101.       }
  102.       sfiterArray[FILTERLEN-1]=lowpulse;
  103.       for(x=0;x<FILTERLEN;x++)
  104.       {
  105.          Serial.println(sfiterArray[x]);
  106.       }
  107.       Serial.println("Aver:");
  108.        Serial.println(Array_Average(sfiterArray,FILTERLEN));
  109.        Serial.println("filter1 END");
  110.       return(Array_Average(sfiterArray,FILTERLEN));
  111.       
  112.   }


  113. }
  114. /*END: filter program : 20130521 */

  115. int x=0; //simulated sensor output
  116. int sampling=1;
  117. int transfering=0;

  118. /* Modbus para */
  119. int retval;
  120. int data[10];
  121. int tt[30];  //int changed to unsigned int

  122. void loop() {

  123.   int i;     
  124.   /* example, this will write some data in the first 10 registers of slave 1  */
  125.   //                retval = preset_multiple_registers(1,1,10, data);

  126.   //                data[0] = retval;
  127.   //                data[1]++;
  128.   //                data[8]=0xdead;
  129.   //                data[9] = 0xbeaf;
  130.   //                delay(500);
  131.   //int read_holding_registers(int slave, int start_addr, int count,int *dest, int dest_size);               
  132.   //                retval = read_holding_registers(2,1, 1,tt,6);      
  133.   retval = read_holding_registers(1, 0x49, 6, tt, 1); // 1:5,2:7,3:9
  134.   //                delay(1000);
  135.   //                Serial.print("receve flag=");               
  136.   //                Serial.println(retval);


  137.   int     Voltage  = tt[0];
  138.           Voltage  = Voltage / 100;
  139.   float   Amp      = tt[1];
  140.           Amp      = Amp / 1000;
  141.   int     Watt     = tt[2];
  142.   //long y=x0*65536+x1;
  143.   unsigned   int Kwhh = (unsigned int)tt[3];
  144.   //unsigned int Kwhh = (unsigned int)65535; //test maximum
  145.   unsigned   int Kwhl = (unsigned int)tt[4];
  146.   unsigned   long kwhA = (unsigned long) Kwhh *65536 + Kwhl;
  147.   //    unsigned  long kwhA = Kwhh <<16 + Kwhl;
  148.   float Kwh = kwhA;
  149.   Kwh = Kwh / 3200;
  150.   //    double Kwh  = kwhA / 3200; //Kwh  = kwh / 32;
  151.   //    int Kwh     = tt[4];
  152.   float Pf = tt[5];
  153.         Pf = Pf / 1000;
  154.   float Cabon  = tt[5];
  155.         Cabon  = Cabon / 1000;
  156.         

  157.   Serial.print(Voltage);
  158.   Serial.print(Amp);
  159.   Serial.print(Watt);
  160.   Serial.print(Kwh);
  161.   Serial.print(Pf);
  162.   Serial.print(Cabon);
  163.   

  164. // 4 Parameter: watt / kwh / Amp / Voltage / Pf

  165.       lwc->append("T21", Kwh);
  166.       lwc->append("T22", Watt);
  167.       lwc->append("T23", Amp);
  168.       lwc->append("T24", Voltage);
  169.       lwc->append("T25", Pf);
  170. //      lwc->append("06", Cabon);
  171.       
  172.      
  173.         lwc->send();   
  174.         delay(15000);
  175. }

  176. // this method makes a HTTP connection to the server:


  177. /****************************************************************************
  178. * BEGIN MODBUS RTU MASTER FUNCTIONS
  179. ****************************************************************************/

  180. //#define TIMEOUT 1000          /* 1 second */
  181. #define TIMEOUT 10000          /* 10 second */
  182. #define MAX_READ_REGS 125
  183. #define MAX_WRITE_REGS 125
  184. #define MAX_RESPONSE_LENGTH 256
  185. #define PRESET_QUERY_SIZE 256
  186. /* errors */
  187. #define PORT_ERROR -5

  188. /*
  189. CRC

  190. INPUTS:
  191. buf   ->  Array containing message to be sent to controller.           
  192. start ->  Start of loop in crc counter, usually 0.
  193. cnt   ->  Amount of bytes in message being sent to controller/
  194. OUTPUTS:
  195. temp  ->  Returns crc byte for message.
  196. COMMENTS:
  197. This routine calculates the crc high and low byte of a message.
  198. Note that this crc is only used for Modbus, not Modbus+ etc.
  199. ****************************************************************************/

  200. unsigned int crc(unsigned char *buf, int start, int cnt)
  201. {
  202.   int i, j;
  203.   unsigned temp, temp2, flag;

  204.   temp = 0xFFFF;

  205.   for (i = start; i < cnt; i++) {
  206.     temp = temp ^ buf[i];

  207.     for (j = 1; j <= 8; j++) {
  208.       flag = temp & 0x0001;
  209.       temp = temp >> 1;
  210.       if (flag)
  211.         temp = temp ^ 0xA001;
  212.     }
  213.   }

  214.   /* Reverse byte order. */

  215.   temp2 = temp >> 8;
  216.   temp = (temp << 8) | temp2;
  217.   temp &= 0xFFFF;

  218.   return (temp);
  219. }


  220. /***********************************************************************
  221. *
  222. *      The following functions construct the required query into
  223. *      a modbus query packet.
  224. *
  225. ***********************************************************************/

  226. #define REQUEST_QUERY_SIZE 6     /* the following packets require          */
  227. #define CHECKSUM_SIZE 2          /* 6 unsigned chars for the packet plus   */
  228. /* 2 for the checksum.                    */

  229. void build_request_packet(int slave, int function, int start_addr,
  230. int count, unsigned char *packet)
  231. {
  232.   packet[0] = slave;
  233.   packet[1] = function;
  234.   start_addr -= 1;
  235.   packet[2] = start_addr >> 8;
  236.   packet[3] = start_addr & 0x00ff;
  237.   packet[4] = count >> 8;
  238.   packet[5] = count & 0x00ff;

  239.   //below test only
  240.   //        packet[0] =0x01;
  241.   //        packet[1] = 0x03;
  242.   //        packet[2] = 0;
  243.   //        packet[3] = 0x48;
  244.   //        packet[4] = 0;
  245.   //        packet[5] = 0x02;
  246. }

  247. /*************************************************************************
  248. *
  249. * modbus_query( packet, length)
  250. *
  251. * Function to add a checksum to the end of a packet.
  252. * Please note that the packet array must be at least 2 fields longer than
  253. * string_length.
  254. **************************************************************************/

  255. void modbus_query(unsigned char *packet, size_t string_length)
  256. {
  257.   int temp_crc;

  258.   temp_crc = crc(packet, 0, string_length);

  259.   packet[string_length++] = temp_crc >> 8;
  260.   packet[string_length++] = temp_crc & 0x00FF;
  261.   packet[string_length] = 0;
  262. }



  263. /***********************************************************************
  264. *
  265. * send_query(query_string, query_length )
  266. *
  267. * Function to send a query out to a modbus slave.
  268. ************************************************************************/

  269. int send_query(unsigned char *query, size_t string_length)
  270. {

  271.   int i;

  272.   modbus_query(query, string_length);
  273.   string_length += 2;

  274.   for (i = 0; i < string_length; i++) {
  275.     //                Serial.print(query[i], HEX); //Orginal
  276.     Serial.write(query[i]); //JingLi

  277.   }
  278.   /* without the following delay, the reading of the response might be wrong
  279.    * apparently, */
  280.   delay(200);            /* FIXME: value to use? */

  281.   return i;           /* it does not mean that the write was succesful, though */
  282. }


  283. /***********************************************************************
  284. *
  285. *      receive_response( array_for_data )
  286. *
  287. * Function to monitor for the reply from the modbus slave.
  288. * This function blocks for timeout seconds if there is no reply.
  289. *
  290. * Returns:     Total number of characters received.
  291. ***********************************************************************/

  292. int receive_response(unsigned char *received_string)
  293. {

  294.   int bytes_received = 0;
  295.   int i = 0;
  296.   /* wait for a response; this will block! */
  297.   while(Serial.available() == 0) {
  298.     delay(1);
  299.     if (i++ > TIMEOUT)
  300.       return bytes_received;
  301.   }
  302.   delay(200);
  303.   /* FIXME: does Serial.available wait 1.5T or 3.5T before exiting the loop? */
  304.   while(Serial.available()) {
  305.     received_string[bytes_received] = Serial.read();
  306.     //                Serial.print(bytes_received);                       //only test
  307.     //                Serial.print("-");                                //only test
  308.     //                Serial.println(received_string[bytes_received]);  //only test
  309.     bytes_received++;
  310.     if (bytes_received >= MAX_RESPONSE_LENGTH)
  311.       return PORT_ERROR;
  312.   }   
  313.   //Serial.print("bytes_received=");
  314.   //Serial.println(bytes_received);
  315.   return (bytes_received);
  316. }


  317. /*********************************************************************
  318. *
  319. *      modbus_response( response_data_array, query_array )
  320. *
  321. * Function to the correct response is returned and that the checksum
  322. * is correct.
  323. *
  324. * Returns:     string_length if OK
  325. *           0 if failed
  326. *           Less than 0 for exception errors
  327. *
  328. *      Note: All functions used for sending or receiving data via
  329. *            modbus return these return values.
  330. *
  331. **********************************************************************/

  332. int modbus_response(unsigned char *data, unsigned char *query)
  333. {
  334.   int response_length;
  335.   int i;
  336.   unsigned int crc_calc = 0;
  337.   unsigned int crc_received = 0;
  338.   unsigned char recv_crc_hi;
  339.   unsigned char recv_crc_lo;

  340.   do {        // repeat if unexpected slave replied
  341.     response_length = receive_response(data);
  342.   }
  343.   while ((response_length > 0) && (data[0] != query[0]));
  344.   //      for (i = 0; i <response_length; i++) {           Serial.print(data[i]);Serial.print("---");   Serial.println(query[i]);}                       //only test

  345.   if (response_length) {


  346.     crc_calc = crc(data, 0, response_length - 2);

  347.     recv_crc_hi = (unsigned) data[response_length - 2];
  348.     recv_crc_lo = (unsigned) data[response_length - 1];

  349.     crc_received = data[response_length - 2];
  350.     crc_received = (unsigned) crc_received << 8;
  351.     crc_received =
  352.       crc_received | (unsigned) data[response_length - 1];


  353.     /*********** check CRC of response ************/

  354.     if (crc_calc != crc_received) {
  355.       response_length = 0;
  356.       //                       Serial.println("CRC erro");                       //only test
  357.     }



  358.     /********** check for exception response *****/

  359.     if (response_length && data[1] != query[1]) {
  360.       response_length = 0 - data[2];
  361.     }
  362.   }
  363.   return (response_length);
  364. }


  365. /************************************************************************
  366. *
  367. *      read_reg_response
  368. *
  369. *      reads the response data from a slave and puts the data into an
  370. *      array.
  371. *
  372. ************************************************************************/

  373. int read_reg_response(int *dest, int dest_size, unsigned char *query)
  374. {

  375.   unsigned char data[MAX_RESPONSE_LENGTH];
  376.   int raw_response_length;
  377.   int temp, i;

  378.   raw_response_length = modbus_response(data, query);
  379.   if (raw_response_length > 0)
  380.     raw_response_length -= 2;

  381.   if (raw_response_length > 0) {
  382.     /* FIXME: data[2] * 2 ???!!! data[2] isn't already the byte count (number of registers * 2)?! */
  383.     for (i = 0;
  384.                i < (data[2] * 2) && i < (raw_response_length / 2);
  385.                i++) {

  386.       /* shift reg hi_byte to temp */
  387.       temp = data[3 + i * 2] << 8;
  388.       /* OR with lo_byte           */
  389.       temp = temp | data[4 + i * 2];

  390.       dest[i] = temp;
  391.     }
  392.   }
  393.   return (raw_response_length);
  394. }


  395. /***********************************************************************
  396. *
  397. *      preset_response
  398. *
  399. *      Gets the raw data from the input stream.
  400. *
  401. ***********************************************************************/

  402. int preset_response(unsigned char *query)
  403. {
  404.   unsigned char data[MAX_RESPONSE_LENGTH];
  405.   int raw_response_length;

  406.   raw_response_length = modbus_response(data, query);

  407.   return (raw_response_length);
  408. }


  409. /************************************************************************
  410. *
  411. *      read_holding_registers
  412. *
  413. *      Read the holding registers in a slave and put the data into
  414. *      an array.
  415. *
  416. *************************************************************************/

  417. int read_holding_registers(int slave, int start_addr, int count,
  418. int *dest, int dest_size)
  419. {
  420.   int function = 0x03;      /* Function: Read Holding Registers */
  421.   int ret;

  422.   unsigned char packet[REQUEST_QUERY_SIZE + CHECKSUM_SIZE];

  423.   if (count > MAX_READ_REGS) {
  424.     count = MAX_READ_REGS;
  425.   }

  426.   build_request_packet(slave, function, start_addr, count, packet);

  427.   if (send_query(packet, REQUEST_QUERY_SIZE) > -1) {
  428.     ret = read_reg_response(dest, dest_size, packet);
  429.   }
  430.   else {

  431.     ret = -1;
  432.   }

  433.   return (ret);
  434. }


  435. /************************************************************************
  436. *
  437. *      preset_multiple_registers
  438. *
  439. *      Write the data from an array into the holding registers of a
  440. *      slave.
  441. *
  442. *************************************************************************/

  443. int preset_multiple_registers(int slave, int start_addr,
  444. int reg_count, int *data)
  445. {
  446.   int function = 0x10;      /* Function 16: Write Multiple Registers */
  447.   int byte_count, i, packet_size = 6;
  448.   int ret;

  449.   unsigned char packet[PRESET_QUERY_SIZE];

  450.   if (reg_count > MAX_WRITE_REGS) {
  451.     reg_count = MAX_WRITE_REGS;
  452.   }

  453.   build_request_packet(slave, function, start_addr, reg_count, packet);
  454.   byte_count = reg_count * 2;
  455.   packet[6] = (unsigned char)byte_count;

  456.   for (i = 0; i < reg_count; i++) {
  457.     packet_size++;
  458.     packet[packet_size] = data[i] >> 8;
  459.     packet_size++;
  460.     packet[packet_size] = data[i] & 0x00FF;
  461.   }

  462.   packet_size++;
  463.   if (send_query(packet, packet_size) > -1) {
  464.     ret = preset_response(packet);
  465.   }
  466.   else {
  467.     ret = -1;
  468.   }

  469.   return (ret);
  470. }


复制代码


本人知识有限,东拼西凑,朋友帮忙,希望能给大家抛砖引玉!

在这里,特别要感谢我的好朋友JingLi和LinZai,在“网络电量表”原型开发过程中的大力协助。


图片说明一下:第一张是“网络电能表”在乐联网的截图,第二张是家里电表的运行数字,第三张是使用到的互感器版本电量模块。

2013.09.01 更新程序代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2013-7-3 08:44:25 | 显示全部楼层
这个模块到底是个什么模块,有没有淘宝链接的说?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-3 08:54:13 来自手机 | 显示全部楼层
Cupid 发表于 2013-7-3 08:44:25
这个模块到底是个什么模块,有没有淘宝链接的说?

你去某宝,搜一下“立天电子工作室”,或者用网上很多的带数据接口的轨道电能表也成。来自: Android客户端
回复 支持 反对

使用道具 举报

发表于 2013-7-3 10:58:58 | 显示全部楼层
这个是安装在家里入户总线上吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-3 12:15:03 来自手机 | 显示全部楼层
zwltanf 发表于 2013-7-3 10:58
这个是安装在家里入户总线上吗?

这个是互感器版本,不需要动电表和主空开,只要将互感器穿入火线(也说可以任意一棵主线),然后接电即可。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-5 00:17:55 | 显示全部楼层
zwltanf 发表于 2013-7-3 10:58
这个是安装在家里入户总线上吗?

现在有一朋友感兴趣,大家准备凑一起买一批模块一起玩。
回复 支持 反对

使用道具 举报

发表于 2013-7-5 09:59:18 | 显示全部楼层
muggle 发表于 2013-7-5 00:17
现在有一朋友感兴趣,大家准备凑一起买一批模块一起玩。

在哪里买?  工作有比较忙,才看到
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-5 11:37:41 来自手机 | 显示全部楼层
zwltanf 发表于 2013-7-5 09:59:18

在哪里买?  工作有比较忙,才看到

你发站内信,给我你的联系方式,今天晚些联系你。
我这次用这个模块,发现一些安装问题,已经联系卖家延长互感器连线,位置可以更灵活。这次预订了十块,应该还有一两块没定死,有兴趣可以参与一起来玩。来自: Android客户端
回复 支持 反对

使用道具 举报

发表于 2013-7-5 19:54:16 来自手机 | 显示全部楼层
必须顶一下啊
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-9 21:33:58 | 显示全部楼层
新浪微博的电量记录推送页面“网络电量表”已经开通,每天定期推送电量数据记录:
http://weibo.com/u/1665750791
回复 支持 反对

使用道具 举报

发表于 2013-7-9 23:11:00 | 显示全部楼层
请问楼主,那个互感器模块哪里买的?多少钱?
回复 支持 反对

使用道具 举报

发表于 2013-7-10 09:58:14 | 显示全部楼层
这个模块是否经过安全认证?安装过程是否安全?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-10 12:11:18 来自手机 | 显示全部楼层
raiseyu 发表于 2013-7-9 23:11:00
请问楼主,那个互感器模块哪里买的?多少钱?

这个模块138元,可以上某宝搜立天电子。来自: Android客户端
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-10 12:13:30 来自手机 | 显示全部楼层
飞翔的红猪 发表于 2013-7-10 09:58:14
这个模块是否经过安全认证?安装过程是否安全?

这个模块是才用互感器结构,安装相对方便,放置在空开下口即可。安全认证,倒没考虑过,几款模块用着还好,电量计量都是成熟方案。这只是自己使用感受,详细请咨询卖家。来自: Android客户端
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-7-10 12:16:05 来自手机 | 显示全部楼层
大家很多关注这个网络电量表,尤其是电量模块。最近定制改造了几只,比现在这款更方便安装,到手以后会给大家上图展示。来自: Android客户端
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-18 16:36 , Processed in 0.047852 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表