极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 42458|回复: 24

可视化网络电表搭建攻略

[复制链接]
发表于 2013-8-13 15:35:06 | 显示全部楼层 |阅读模式
本帖最后由 瘦网虫 于 2013-11-8 15:16 编辑

标题起得比较唬人,请无视。

×友情提示,修改电路前,一定要断开电源总开关×

你想象过看着家里的电器用电的样子吗?
你知道你每月那几天交的钱都去了哪里了吗?
你知道是什么东东在偷偷的用你的电吗?

如果你感兴趣,下面的文章适合你。

电,对于很多人来说是个很神秘,很危险,很神奇的东西。现在通过下面的攻略,你也可以拥有这样神奇的超能力,看到家里的电跑到哪里去了,是不是很想要?

====小广告====
你需要:
一个测电笔
一个十字口螺丝刀
一个平口螺丝刀
一把尖嘴钳
一个电量测量模块
一个通讯底板(我用的乐联网的E-KIT),你也可以使用任何一种arduino+w5100模块来搭建。

====广告结束===

先看看效果图(据说近期会有新版的展示界面)
在线链接:
http://www.lewei50.com/u/g/1979


新版展示界面:


看到下面的锯齿状图形了吗?那就是你的冰箱在努力保持西瓜的新鲜。
几个用电高峰,是空调们在为主人降温。
用电量怎么总是高于0呢?那是你的无线路由器在保持家里的网络时刻畅通。

现在分步骤来实现它:
1断电
要断开家里空气开关的总闸,如果有室外的总闸,那就拉室外的总闸,保证家里是没有电的。
操作时严禁一只手碰火线,一只手碰零线。

2接线
打开家里的配电箱,找到总的进户的火线,拆开,把电量测量模块的圈圈套在这个火线上,专业术语是“互感器”。并把火线按照原来的位置接回去。

按照接线说明图,连接好测量模块、通讯模块和arduino。
3通电
如果你的操作正确,这时候推上你家的空气开关总闸,是不会有任何反应的。如果有问题,会跳闸。
4注册网站及设置对应传感器
http://www.lewei50.com/
注册及配置传感器过程不详细说明了。简单说下我的传感器的命名,你也可以有你自己的。

5刷代码
刷代码是为了从通讯模块里面把电量等数据读出来,并上传到乐联网上。

代码中使用了乐联网的类库,从这里下载:
http://www.github.com/lewei50/LeWeiClient/


  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. // 这里的名字要跟你之前在网站上设置的对应起来

  166.       lwc->append("kwh", Kwh);
  167.       lwc->append("w", Watt);
  168.       lwc->append("a", Amp);
  169.       lwc->append("v", Voltage);
  170.       lwc->append("pf", Pf);
  171. //      lwc->append("06", Cabon);
  172.       
  173.      
  174.         lwc->send();   
  175.         delay(15000);
  176. }

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


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

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

  189. /*
  190. CRC

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

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

  205.   temp = 0xFFFF;

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

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

  215.   /* Reverse byte order. */

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

  219.   return (temp);
  220. }


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

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

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

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

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

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

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

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



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

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

  272.   int i;

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

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

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

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


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

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

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


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

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

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

  346.   if (response_length) {


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

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

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


  354.     /*********** check CRC of response ************/

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



  359.     /********** check for exception response *****/

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


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

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

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

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

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

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

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


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

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

  407.   raw_response_length = modbus_response(data, query);

  408.   return (raw_response_length);
  409. }


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

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

  423.   unsigned char packet[REQUEST_QUERY_SIZE + CHECKSUM_SIZE];

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

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

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

  432.     ret = -1;
  433.   }

  434.   return (ret);
  435. }


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

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

  450.   unsigned char packet[PRESET_QUERY_SIZE];

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

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

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

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

  470.   return (ret);
  471. }
复制代码


6将电量可视化、数字化之后,你可以做很多的事情,自己琢磨吧~

Enjoy it~

本帖子中包含更多资源

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

x
回复

使用道具 举报

发表于 2013-8-13 16:24:40 | 显示全部楼层
好主意,贴个系统示例吧.
回复 支持 反对

使用道具 举报

发表于 2013-8-13 19:40:12 | 显示全部楼层
好主意,贴个系统示例
回复 支持 反对

使用道具 举报

发表于 2013-8-14 08:44:39 | 显示全部楼层
一个电量测量模块  ,这个东西在哪儿能买到,有链接没
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-14 09:02:39 | 显示全部楼层
Cupid 发表于 2013-8-14 08:44
一个电量测量模块  ,这个东西在哪儿能买到,有链接没


我是参加乐联网的这个网络电表的活动,免费获得的。
家庭能耗管理活动 - 乐联网 - 乐为物联开放平台 - 物联网运营专家
http://www.lewei50.com/event/detail/1

如果你不着急,可以等下次参加乐联网组织网络电表的活动,可以优惠购买。

如果你着急,可以加这个QQ:29591997(老顽童)咨询(不是我的QQ),这次的网络电表活动就是他和乐联网联手组织的。
回复 支持 反对

使用道具 举报

发表于 2013-8-14 09:39:25 | 显示全部楼层
虫哥的帖子必须顶!
回复 支持 反对

使用道具 举报

发表于 2013-8-14 10:02:18 | 显示全部楼层
必顺顶一下啊
回复 支持 反对

使用道具 举报

发表于 2013-8-14 10:38:28 | 显示全部楼层
不错,以后可以自己监控家里用电了,具体用多少电应该监控不到吧??
回复 支持 反对

使用道具 举报

发表于 2013-8-14 10:42:28 | 显示全部楼层
电量测量模块  具体叫什么名字  我想淘宝上入一块
回复 支持 反对

使用道具 举报

发表于 2013-8-14 13:14:44 | 显示全部楼层
我喜欢这样的图文制作,清晰,易懂,适合初学者模仿,我准备学着做一套,请问互感器的购买和使用方法,求作者指导,谢谢。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-14 13:34:25 | 显示全部楼层
本帖最后由 瘦网虫 于 2013-8-14 13:37 编辑
学慧放弃 发表于 2013-8-14 10:38
不错,以后可以自己监控家里用电了,具体用多少电应该监控不到吧??


有个总的用电量,第一个值就是。是累加值,其实就相当于你家电表的总读数。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-14 13:35:45 | 显示全部楼层
flashria 发表于 2013-8-14 10:42
电量测量模块  具体叫什么名字  我想淘宝上入一块

可以加这个QQ:29591997(老顽童)咨询(不是我的QQ),或者等待参加下一次的网络电表活动。
回复 支持 反对

使用道具 举报

发表于 2013-8-14 13:56:01 | 显示全部楼层
这个也顶一下。
回复 支持 反对

使用道具 举报

发表于 2013-8-14 15:04:20 | 显示全部楼层
电流互感直接上ArduinoAD就可以了,不一定485转来转去。
回复 支持 反对

使用道具 举报

发表于 2013-8-14 21:33:35 | 显示全部楼层
郑重提醒:

市电有风险,动电请谨慎。。。


大家有兴趣的,可以移步“网络电量表”@新浪微博了解项目进展,欢迎加入“59162154”群进行咨询交流。

老顽童
回复 支持 反对

使用道具 举报

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

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

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 14:21 , Processed in 0.055855 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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