Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TinyGsmClientXBee.h 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. /**
  2. * file TinyGsmClientXBee.h
  3. * author Volodymyr Shymanskyy
  4. * license LGPL-3.0
  5. * copyright Copyright (c) 2016 Volodymyr Shymanskyy
  6. * date Nov 2016
  7. */
  8. #ifndef TinyGsmClientXBee_h
  9. #define TinyGsmClientXBee_h
  10. //#define TINY_GSM_DEBUG Serial
  11. #if !defined(TINY_GSM_RX_BUFFER)
  12. #define TINY_GSM_RX_BUFFER 256
  13. #endif
  14. #define TINY_GSM_MUX_COUNT 1 // Multi-plexing isn't supported using command mode
  15. #include "TinyGsmCommon.h"
  16. #define GSM_NL "\r"
  17. static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
  18. static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
  19. enum SimStatus {
  20. SIM_ERROR = 0,
  21. SIM_READY = 1,
  22. SIM_LOCKED = 2,
  23. };
  24. enum XBeeType {
  25. S6B = 0,
  26. LTEC1 = 1,
  27. };
  28. enum RegStatus {
  29. REG_UNREGISTERED = 0,
  30. REG_SEARCHING = 2,
  31. REG_DENIED = 3,
  32. REG_OK_HOME = 1,
  33. REG_OK_ROAMING = 5,
  34. REG_UNKNOWN = 4,
  35. };
  36. class TinyGsm
  37. {
  38. public:
  39. class GsmClient : public Client
  40. {
  41. friend class TinyGsm;
  42. public:
  43. GsmClient() {}
  44. GsmClient(TinyGsm& modem, uint8_t mux = 0)
  45. {
  46. init(&modem, mux);
  47. }
  48. bool init(TinyGsm* modem, uint8_t mux = 0)
  49. {
  50. this->at = modem;
  51. this->mux = mux;
  52. sock_connected = false;
  53. at->sockets[mux] = this;
  54. return true;
  55. }
  56. public:
  57. virtual int connect(const char *host, uint16_t port)
  58. {
  59. at->streamClear(); // Empty anything remaining in the buffer;
  60. at->commandMode();
  61. sock_connected = at->modemConnect(host, port, mux, false);
  62. at->writeChanges();
  63. at->exitCommand();
  64. return sock_connected;
  65. }
  66. virtual int connect(IPAddress ip, uint16_t port)
  67. {
  68. at->streamClear(); // Empty anything remaining in the buffer;
  69. at->commandMode();
  70. sock_connected = at->modemConnect(ip, port, mux, false);
  71. at->writeChanges();
  72. at->exitCommand();
  73. return sock_connected;
  74. }
  75. // This is a hack to shut the socket by setting the timeout to zero and
  76. // then sending an empty line to the server.
  77. virtual void stop()
  78. {
  79. at->streamClear(); // Empty anything remaining in the buffer;
  80. at->commandMode();
  81. at->sendAT(GF("TM0")); // Set socket timeout to 0;
  82. at->waitResponse();
  83. at->writeChanges();
  84. at->exitCommand();
  85. at->modemSend("", 1, mux);
  86. at->commandMode();
  87. at->sendAT(GF("TM64")); // Set socket timeout back to 10seconds;
  88. at->waitResponse();
  89. at->writeChanges();
  90. at->exitCommand();
  91. at->streamClear(); // Empty anything remaining in the buffer;
  92. sock_connected = false;
  93. }
  94. virtual size_t write(const uint8_t *buf, size_t size)
  95. {
  96. TINY_GSM_YIELD();
  97. //at->maintain();
  98. return at->modemSend(buf, size, mux);
  99. }
  100. virtual size_t write(uint8_t c)
  101. {
  102. return write(&c, 1);
  103. }
  104. virtual int available()
  105. {
  106. TINY_GSM_YIELD();
  107. return at->stream.available();
  108. }
  109. virtual int read(uint8_t *buf, size_t size)
  110. {
  111. TINY_GSM_YIELD();
  112. return at->stream.readBytes(buf, size);
  113. }
  114. virtual int read()
  115. {
  116. TINY_GSM_YIELD();
  117. return at->stream.read();
  118. }
  119. virtual int peek()
  120. {
  121. return at->stream.peek();
  122. }
  123. virtual void flush()
  124. {
  125. at->stream.flush();
  126. }
  127. virtual uint8_t connected()
  128. {
  129. if (available()) {
  130. return true;
  131. }
  132. return sock_connected;
  133. }
  134. virtual operator bool()
  135. {
  136. return connected();
  137. }
  138. /*
  139. * Extended API
  140. */
  141. String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
  142. private:
  143. TinyGsm* at;
  144. uint8_t mux;
  145. bool sock_connected;
  146. };
  147. class GsmClientSecure : public GsmClient
  148. {
  149. public:
  150. GsmClientSecure() {}
  151. GsmClientSecure(TinyGsm& modem, uint8_t mux = 1)
  152. : GsmClient(modem, mux)
  153. {}
  154. public:
  155. virtual int connect(const char *host, uint16_t port)
  156. {
  157. at->streamClear(); // Empty anything remaining in the buffer;
  158. at->commandMode();
  159. sock_connected = at->modemConnect(host, port, mux, true);
  160. at->writeChanges();
  161. at->exitCommand();
  162. return sock_connected;
  163. }
  164. virtual int connect(IPAddress ip, uint16_t port)
  165. {
  166. at->streamClear(); // Empty anything remaining in the buffer;
  167. at->commandMode();
  168. sock_connected = at->modemConnect(ip, port, mux, true);
  169. at->writeChanges();
  170. at->exitCommand();
  171. return sock_connected;
  172. }
  173. };
  174. public:
  175. explicit TinyGsm(Stream& stream)
  176. : stream(stream)
  177. {
  178. memset(sockets, 0, sizeof(sockets));
  179. }
  180. /*
  181. * Basic functions
  182. */
  183. bool begin()
  184. {
  185. return init();
  186. }
  187. bool init()
  188. {
  189. guardTime = 1100;
  190. commandMode();
  191. sendAT(GF("AP0")); // Put in transparent mode
  192. waitResponse();
  193. sendAT(GF("GT64")); // shorten the guard time to 100ms
  194. waitResponse();
  195. writeChanges();
  196. sendAT(GF("HS")); // Get the "Hardware Series"; 0x601 for S6B (Wifi)
  197. // wait for the response
  198. unsigned long startMillis = millis();
  199. while (!stream.available() && millis() - startMillis < 1000) {};
  200. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  201. exitCommand();
  202. if (res == "601") {
  203. beeType = S6B;
  204. } else {
  205. beeType = LTEC1;
  206. }
  207. guardTime = 125;
  208. return true;
  209. }
  210. bool testAT(unsigned long timeout = 10000L)
  211. {
  212. for (unsigned long start = millis(); millis() - start < timeout; ) {
  213. if (commandMode()) {
  214. sendAT();
  215. if (waitResponse(200) == 1) {
  216. return true;
  217. }
  218. exitCommand();
  219. }
  220. delay(100);
  221. }
  222. return false;
  223. }
  224. void maintain() {}
  225. bool factoryDefault()
  226. {
  227. commandMode();
  228. sendAT(GF("RE"));
  229. bool ret_val = waitResponse() == 1;
  230. writeChanges();
  231. exitCommand();
  232. return ret_val;
  233. }
  234. bool hasSSL()
  235. {
  236. if (beeType == S6B) {
  237. return false;
  238. } else {
  239. return true;
  240. }
  241. }
  242. /*
  243. * Power functions
  244. */
  245. bool restart()
  246. {
  247. commandMode();
  248. sendAT(GF("FR"));
  249. if (waitResponse() != 1) {
  250. return false;
  251. }
  252. delay (2000); // Actually resets about 2 seconds later
  253. for (unsigned long start = millis(); millis() - start < 60000L; ) {
  254. if (commandMode()) {
  255. exitCommand();
  256. return true;
  257. }
  258. }
  259. exitCommand();
  260. return false;;
  261. }
  262. void setupPinSleep()
  263. {
  264. commandMode();
  265. sendAT(GF("SM"),1);
  266. waitResponse();
  267. if (beeType == S6B) {
  268. sendAT(GF("SO"),200);
  269. waitResponse();
  270. }
  271. writeChanges();
  272. exitCommand();
  273. }
  274. /*
  275. * SIM card functions
  276. */
  277. bool simUnlock(const char *pin) // Not supported
  278. {
  279. return false;
  280. }
  281. String getSimCCID()
  282. {
  283. commandMode();
  284. sendAT(GF("S#"));
  285. // wait for the response
  286. unsigned long startMillis = millis();
  287. while (!stream.available() && millis() - startMillis < 1000) {};
  288. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  289. exitCommand();
  290. return res;
  291. }
  292. String getIMEI()
  293. {
  294. commandMode();
  295. sendAT(GF("IM"));
  296. // wait for the response
  297. unsigned long startMillis = millis();
  298. while (!stream.available() && millis() - startMillis < 1000) {};
  299. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  300. exitCommand();
  301. return res;
  302. }
  303. SimStatus getSimStatus(unsigned long timeout = 10000L)
  304. {
  305. return SIM_READY; // unsupported
  306. }
  307. RegStatus getRegistrationStatus()
  308. {
  309. commandMode();
  310. sendAT(GF("AI"));
  311. // wait for the response
  312. unsigned long startMillis = millis();
  313. while (!stream.available() && millis() - startMillis < 1000) {};
  314. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  315. exitCommand();
  316. if(res == GF("0")) {
  317. return REG_OK_HOME;
  318. }
  319. else if(res == GF("13") || res == GF("2A")) {
  320. return REG_UNREGISTERED;
  321. }
  322. else if(res == GF("FF") || res == GF("22") || res == GF("23") ||
  323. res == GF("40") || res == GF("41") || res == GF("42")) {
  324. return REG_SEARCHING;
  325. }
  326. else if(res == GF("24") || res == GF("25") || res == GF("27")) {
  327. return REG_DENIED;
  328. }
  329. else {
  330. return REG_UNKNOWN;
  331. }
  332. }
  333. String getOperator()
  334. {
  335. commandMode();
  336. sendAT(GF("MN"));
  337. // wait for the response
  338. unsigned long startMillis = millis();
  339. while (!stream.available() && millis() - startMillis < 1000) {};
  340. String res = streamReadUntil('\r'); // Does not send an OK, just the result
  341. exitCommand();
  342. return res;
  343. }
  344. /*
  345. * Generic network functions
  346. */
  347. int getSignalQuality()
  348. {
  349. commandMode();
  350. if (beeType == S6B) {
  351. sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity
  352. } else {
  353. sendAT(GF("DB")); // ask for the cell strength in dBm
  354. }
  355. // wait for the response
  356. unsigned long startMillis = millis();
  357. while (!stream.available() && millis() - startMillis < 1000) {};
  358. char buf[2] = {0}; // Set up buffer for response
  359. buf[0] = streamRead();
  360. buf[1] = streamRead();
  361. // DBG(buf[0], buf[1], "\n");
  362. exitCommand();
  363. int intr = strtol(buf, 0, 16);
  364. if (beeType == S6B) {
  365. return -93 + intr; // the maximum sensitivity is -93dBm
  366. } else {
  367. return -1*intr; // need to convert to negative number
  368. }
  369. }
  370. bool isNetworkConnected()
  371. {
  372. RegStatus s = getRegistrationStatus();
  373. return (s == REG_OK_HOME || s == REG_OK_ROAMING);
  374. }
  375. bool waitForNetwork(unsigned long timeout = 60000L)
  376. {
  377. for (unsigned long start = millis(); millis() - start < timeout; ) {
  378. if (isNetworkConnected()) {
  379. return true;
  380. }
  381. delay(250);
  382. }
  383. return false;
  384. }
  385. /*
  386. * WiFi functions
  387. */
  388. bool networkConnect(const char* ssid, const char* pwd)
  389. {
  390. commandMode();
  391. sendAT(GF("EE"), 2); // Set security to WPA2
  392. waitResponse();
  393. sendAT(GF("ID"), ssid);
  394. if (waitResponse() != 1) {
  395. goto fail;
  396. }
  397. sendAT(GF("PK"), pwd);
  398. if (waitResponse() != 1) {
  399. goto fail;
  400. }
  401. writeChanges();
  402. exitCommand();
  403. return true;
  404. fail:
  405. exitCommand();
  406. return false;
  407. }
  408. bool networkDisconnect()
  409. {
  410. return false; // Doesn't support disconnecting
  411. }
  412. String getLocalIP()
  413. {
  414. commandMode();
  415. sendAT(GF("MY"));
  416. String IPaddr;
  417. IPaddr.reserve(16);
  418. // wait for the response
  419. unsigned long startMillis = millis();
  420. while (stream.available() < 8 && millis() - startMillis < 30000) {};
  421. IPaddr = streamReadUntil('\r'); // read result
  422. return IPaddr;
  423. }
  424. IPAddress localIP()
  425. {
  426. return TinyGsmIpFromString(getLocalIP());
  427. }
  428. /*
  429. * GPRS functions
  430. */
  431. bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL)
  432. {
  433. commandMode();
  434. sendAT(GF("AN"), apn); // Set the APN
  435. waitResponse();
  436. writeChanges();
  437. exitCommand();
  438. return true;
  439. }
  440. bool gprsDisconnect() // TODO
  441. {
  442. return false;
  443. }
  444. /*
  445. * Messaging functions
  446. */
  447. String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
  448. bool sendSMS(const String& number, const String& text)
  449. {
  450. commandMode();
  451. sendAT(GF("IP"), 2); // Put in text messaging mode
  452. waitResponse();
  453. sendAT(GF("PH"), number); // Set the phone number
  454. waitResponse();
  455. sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriabe return)
  456. waitResponse();
  457. writeChanges();
  458. exitCommand();
  459. stream.print(text);
  460. stream.write((char)0x0D); // close off with the carriage return
  461. return true;
  462. }
  463. private:
  464. int modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false)
  465. {
  466. sendAT(GF("LA"), host);
  467. String strIP;
  468. strIP.reserve(16);
  469. // wait for the response
  470. unsigned long startMillis = millis();
  471. while (stream.available() < 8 && millis() - startMillis < 30000) {};
  472. strIP = streamReadUntil('\r'); // read result
  473. IPAddress ip = TinyGsmIpFromString(strIP);
  474. return modemConnect(ip, port, mux, ssl);
  475. }
  476. int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false)
  477. {
  478. String host;
  479. host.reserve(16);
  480. host += ip[0];
  481. host += ".";
  482. host += ip[1];
  483. host += ".";
  484. host += ip[2];
  485. host += ".";
  486. host += ip[3];
  487. if (ssl) {
  488. sendAT(GF("IP"), 4); // Put in TCP mode
  489. waitResponse();
  490. } else {
  491. sendAT(GF("IP"), 1); // Put in TCP mode
  492. waitResponse();
  493. }
  494. sendAT(GF("DL"), host); // Set the "Destination Address Low"
  495. waitResponse();
  496. sendAT(GF("DE"), String(port, HEX)); // Set the destination port
  497. int rsp = waitResponse();
  498. return rsp;
  499. }
  500. int modemSend(const void* buff, size_t len, uint8_t mux = 0)
  501. {
  502. stream.write((uint8_t*)buff, len);
  503. stream.flush();
  504. return len;
  505. }
  506. bool modemGetConnected(uint8_t mux = 0)
  507. {
  508. commandMode();
  509. sendAT(GF("AI"));
  510. int res = waitResponse(GF("0"));
  511. exitCommand();
  512. return 1 == res;
  513. }
  514. public:
  515. /* Utilities */
  516. template<typename T>
  517. void streamWrite(T last)
  518. {
  519. stream.print(last);
  520. }
  521. template<typename T, typename... Args>
  522. void streamWrite(T head, Args... tail)
  523. {
  524. stream.print(head);
  525. streamWrite(tail...);
  526. }
  527. int streamRead()
  528. {
  529. return stream.read();
  530. }
  531. String streamReadUntil(char c)
  532. {
  533. TINY_GSM_YIELD();
  534. String return_string = stream.readStringUntil(c);
  535. return_string.trim();
  536. // DBG(return_string, c);
  537. return return_string;
  538. }
  539. void streamClear(void)
  540. {
  541. while (stream.available()) {
  542. streamRead();
  543. }
  544. }
  545. bool commandMode(void)
  546. {
  547. delay(guardTime); // cannot send anything for 1 second before entering command mode
  548. streamWrite(GF("+++")); // enter command mode
  549. // DBG("\r\n+++\r\n");
  550. return 1 == waitResponse(guardTime*2);
  551. }
  552. void writeChanges(void)
  553. {
  554. sendAT(GF("WR")); // Write changes to flash
  555. waitResponse();
  556. sendAT(GF("AC")); // Apply changes
  557. waitResponse();
  558. }
  559. void exitCommand(void)
  560. {
  561. sendAT(GF("CN")); // Exit command mode
  562. waitResponse();
  563. }
  564. template<typename... Args>
  565. void sendAT(Args... cmd)
  566. {
  567. streamWrite("AT", cmd..., GSM_NL);
  568. stream.flush();
  569. TINY_GSM_YIELD();
  570. //DBG("### AT:", cmd...);
  571. }
  572. // TODO: Optimize this!
  573. uint8_t waitResponse(uint32_t timeout, String& data,
  574. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  575. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  576. {
  577. /*String r1s(r1); r1s.trim();
  578. String r2s(r2); r2s.trim();
  579. String r3s(r3); r3s.trim();
  580. String r4s(r4); r4s.trim();
  581. String r5s(r5); r5s.trim();
  582. DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
  583. data.reserve(64);
  584. int index = 0;
  585. unsigned long startMillis = millis();
  586. do {
  587. TINY_GSM_YIELD();
  588. while (stream.available() > 0) {
  589. int a = streamRead();
  590. if (a <= 0) {
  591. continue; // Skip 0x00 bytes, just in case
  592. }
  593. data += (char)a;
  594. if (r1 && data.endsWith(r1)) {
  595. index = 1;
  596. goto finish;
  597. } else if (r2 && data.endsWith(r2)) {
  598. index = 2;
  599. goto finish;
  600. } else if (r3 && data.endsWith(r3)) {
  601. index = 3;
  602. goto finish;
  603. } else if (r4 && data.endsWith(r4)) {
  604. index = 4;
  605. goto finish;
  606. } else if (r5 && data.endsWith(r5)) {
  607. index = 5;
  608. goto finish;
  609. }
  610. }
  611. } while (millis() - startMillis < timeout);
  612. finish:
  613. if (!index) {
  614. data.trim();
  615. data.replace(GSM_NL GSM_NL, GSM_NL);
  616. data.replace(GSM_NL, "\r\n" " ");
  617. if (data.length()) {
  618. DBG("### Unhandled:", data, "\r\n");
  619. } else {
  620. DBG("### NO RESPONSE!\r\n");
  621. }
  622. } else {
  623. data.trim();
  624. data.replace(GSM_NL GSM_NL, GSM_NL);
  625. data.replace(GSM_NL, "\r\n ");
  626. if (data.length()) {
  627. // DBG("<<< ", data);
  628. }
  629. }
  630. return index;
  631. }
  632. uint8_t waitResponse(uint32_t timeout,
  633. GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  634. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  635. {
  636. String data;
  637. return waitResponse(timeout, data, r1, r2, r3, r4, r5);
  638. }
  639. uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
  640. GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
  641. {
  642. return waitResponse(1000, r1, r2, r3, r4, r5);
  643. }
  644. public:
  645. Stream& stream;
  646. protected:
  647. int guardTime;
  648. XBeeType beeType;
  649. GsmClient* sockets[TINY_GSM_MUX_COUNT];
  650. };
  651. #endif