@ -0,0 +1,438 @@ | |||
/** | |||
* @file TinyGsmClient.h | |||
* @author Volodymyr Shymanskyy | |||
* @license LGPL-3.0 | |||
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy | |||
* @date Nov 2016 | |||
*/ | |||
#ifndef TinyGsmClient_h | |||
#define TinyGsmClient_h | |||
#if defined(SPARK) || defined(PARTICLE) | |||
#include "Particle.h" | |||
#elif defined(ARDUINO) | |||
#if ARDUINO >= 100 | |||
#include "Arduino.h" | |||
#else | |||
#include "WProgram.h" | |||
#endif | |||
#endif | |||
#include <Client.h> | |||
#include <TinyGsmFifo.h> | |||
#if defined(__AVR__) | |||
#define GSM_PROGMEM PROGMEM | |||
typedef const __FlashStringHelper* GsmConstStr; | |||
#define FP(x) (reinterpret_cast<GsmConstStr>(x)) | |||
#else | |||
#define GSM_PROGMEM | |||
typedef const char* GsmConstStr; | |||
#define FP(x) x | |||
#undef F | |||
#define F(x) x | |||
#endif | |||
//#define GSM_USE_HEX | |||
#define GSM_RX_BUFFER 64 | |||
#define GSM_NL "\r\n" | |||
static constexpr char GSM_OK[] GSM_PROGMEM = "OK" GSM_NL; | |||
static constexpr char GSM_ERROR[] GSM_PROGMEM = "ERROR" GSM_NL; | |||
class TinyGsmClient | |||
: public Client | |||
{ | |||
typedef TinyGsmFifo<uint8_t, GSM_RX_BUFFER> RxFifo; | |||
#ifdef GSM_DEBUG | |||
template<typename T> | |||
void DBG(T last) { | |||
GSM_DEBUG.println(last); | |||
} | |||
template<typename T, typename... Args> | |||
void DBG(T head, Args... tail) { | |||
GSM_DEBUG.print(head); | |||
GSM_DEBUG.print(' '); | |||
DBG(tail...); | |||
} | |||
#else | |||
#define DBG(...) | |||
#endif | |||
public: | |||
TinyGsmClient(Stream& stream, uint8_t mux = 1) | |||
: stream(stream) | |||
, mux(mux) | |||
, sock_available(0) | |||
, sock_connected(false) | |||
{} | |||
public: | |||
virtual int connect(const char *host, uint16_t port) { | |||
return modemConnect(host, port); | |||
} | |||
virtual int connect(IPAddress ip, uint16_t port) { | |||
String host; host.reserve(16); | |||
host += ip[0]; | |||
host += "."; | |||
host += ip[1]; | |||
host += "."; | |||
host += ip[2]; | |||
host += "."; | |||
host += ip[3]; | |||
return modemConnect(host.c_str(), port); | |||
} | |||
virtual void stop() { | |||
sendAT(F("+CIPCLOSE="), mux); | |||
sock_connected = false; | |||
waitResponse(); | |||
} | |||
virtual size_t write(const uint8_t *buf, size_t size) { | |||
maintain(); | |||
return modemSend(buf, size); | |||
} | |||
virtual size_t write(uint8_t c) { | |||
return write(&c, 1); | |||
} | |||
virtual int available() { | |||
maintain(); | |||
size_t res = rx.size(); | |||
if (res > 0) { | |||
return res; | |||
} | |||
return sock_available; | |||
} | |||
virtual int read(uint8_t *buf, size_t size) { | |||
maintain(); | |||
size_t cnt = 0; | |||
while (cnt < size) { | |||
size_t chunk = min(size-cnt, rx.size()); | |||
if (chunk > 0) { | |||
rx.get(buf, chunk); | |||
buf += chunk; | |||
cnt += chunk; | |||
} else { | |||
modemRead(rx.free()); //TODO: min(rx.free(), sock_available) | |||
} | |||
} | |||
return cnt; | |||
} | |||
virtual int read() { | |||
uint8_t c; | |||
if (read(&c, 1) == 1) { | |||
return c; | |||
} | |||
return -1; | |||
} | |||
virtual int peek() { return -1; } //TODO | |||
virtual void flush() { stream.flush(); } | |||
virtual uint8_t connected() { | |||
maintain(); | |||
return sock_connected; | |||
} | |||
virtual operator bool() { return connected(); } | |||
public: | |||
bool factoryDefault() { | |||
if (!autoBaud()) { | |||
return false; | |||
} | |||
sendAT(F("&FZE0&W")); // Factory + Reset + Echo Off + Write | |||
waitResponse(); | |||
sendAT(F("+IPR=0")); // Auto-baud | |||
waitResponse(); | |||
sendAT(F("+IFC=0,0")); // No Flow Control | |||
waitResponse(); | |||
sendAT(F("+ICF=3,3")); // 8 data 0 parity 1 stop | |||
waitResponse(); | |||
sendAT(F("+CSCLK=0")); // Disable Slow Clock | |||
waitResponse(); | |||
sendAT(F("&W")); // Write configuration | |||
return waitResponse() == 1; | |||
} | |||
bool restart() { | |||
autoBaud(); | |||
sendAT(F("+CFUN=0")); | |||
if (waitResponse(10000L) != 1) { | |||
return false; | |||
} | |||
sendAT(F("+CFUN=1,1")); | |||
if (waitResponse(10000L) != 1) { | |||
return false; | |||
} | |||
delay(3000); | |||
autoBaud(); | |||
sendAT(F("E0")); | |||
if (waitResponse() != 1) { | |||
return false; | |||
} | |||
return 1 == waitResponse(60000, F("Ready")); | |||
} | |||
bool networkConnect(const char* apn, const char* user, const char* pwd) { | |||
autoBaud(); | |||
// AT+CPIN=pin-code | |||
// AT+CREG? | |||
networkDisconnect(); | |||
// AT+CGATT? | |||
// AT+CGATT=1 | |||
sendAT(F("+CIPMUX=1")); | |||
if (waitResponse() != 1) { | |||
return false; | |||
} | |||
sendAT(F("+CIPQSEND=1")); | |||
if (waitResponse() != 1) { | |||
return false; | |||
} | |||
sendAT(F("+CIPRXGET=1")); | |||
if (waitResponse() != 1) { | |||
return false; | |||
} | |||
sendAT(F("+CSTT=\""), apn, F("\",\""), user, F("\",\""), pwd, F("\"")); | |||
if (waitResponse(60000L) != 1) { | |||
return false; | |||
} | |||
sendAT(F("+CIICR")); | |||
if (waitResponse(60000L) != 1) { | |||
return false; | |||
} | |||
sendAT(F("+CIFSR;E0")); | |||
String data; | |||
if (waitResponse(10000L, data) != 1) { | |||
data.replace(GSM_NL, ""); | |||
return false; | |||
} | |||
sendAT(F("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\"")); | |||
if (waitResponse() != 1) { | |||
return false; | |||
} | |||
// AT+CIPSTATUS | |||
return true; | |||
} | |||
bool networkDisconnect() { | |||
sendAT(F("+CIPSHUT")); | |||
return waitResponse(60000L) == 1; | |||
} | |||
bool autoBaud(unsigned long timeout = 10000L) { | |||
for (unsigned long start = millis(); millis() - start < timeout; ) { | |||
sendAT(""); | |||
if (waitResponse() == 1) { | |||
delay(100); | |||
return true; | |||
} | |||
delay(100); | |||
} | |||
return false; | |||
} | |||
void maintain() { | |||
while (stream.available()) { | |||
waitResponse(10); | |||
} | |||
} | |||
private: | |||
int modemConnect(const char* host, uint16_t port) { | |||
sendAT(F("+CIPSTART="), mux, ',', F("\"TCP"), F("\",\""), host, F("\","), port); | |||
sock_connected = (1 == waitResponse(75000L, F("CONNECT OK" GSM_NL), F("CONNECT FAIL" GSM_NL), F("ALREADY CONNECT" GSM_NL))); | |||
return sock_connected; | |||
} | |||
int modemSend(const void* buff, size_t len) { | |||
sendAT(F("+CIPSEND="), mux, ',', len); | |||
if (waitResponse(F(">")) != 1) { | |||
return -1; | |||
} | |||
stream.write((uint8_t*)buff, len); | |||
if (waitResponse(F(GSM_NL "DATA ACCEPT:")) != 1) { | |||
return -1; | |||
} | |||
stream.readStringUntil(','); | |||
String data = stream.readStringUntil('\n'); | |||
return data.toInt(); | |||
} | |||
size_t modemRead(size_t size) { | |||
#ifdef GSM_USE_HEX | |||
sendAT(F("+CIPRXGET=3,"), mux, ',', size); | |||
if (waitResponse(F("+CIPRXGET: 3,")) != 1) { | |||
return 0; | |||
} | |||
#else | |||
sendAT(F("+CIPRXGET=2,"), mux, ',', size); | |||
if (waitResponse(F("+CIPRXGET: 2,")) != 1) { | |||
return 0; | |||
} | |||
#endif | |||
stream.readStringUntil(','); // Skip mux | |||
size_t len = stream.readStringUntil(',').toInt(); | |||
sock_available = stream.readStringUntil('\n').toInt(); | |||
for (size_t i=0; i<len; i++) { | |||
#ifdef GSM_USE_HEX | |||
while (stream.available() < 2) { delay(1); } | |||
char buf[4] = { 0, }; | |||
buf[0] = stream.read(); | |||
buf[1] = stream.read(); | |||
char c = strtol(buf, NULL, 16); | |||
#else | |||
while (stream.available() < 1) { delay(1); } | |||
char c = stream.read(); | |||
#endif | |||
rx.put(c); | |||
} | |||
waitResponse(); | |||
return len; | |||
} | |||
size_t modemGetAvailable() { | |||
sendAT(F("+CIPRXGET=4,"), mux); | |||
size_t result = 0; | |||
for (byte i = 0; i < 2; i++) { | |||
int res = waitResponse(F("+CIPRXGET: 4"), FP(GSM_OK), FP(GSM_ERROR)); | |||
if (res == 1) { | |||
stream.readStringUntil(','); | |||
stream.readStringUntil(','); | |||
result = stream.readStringUntil('\n').toInt(); | |||
} else if (res == 2) { | |||
} else { | |||
return result; | |||
} | |||
} | |||
if (!result) { | |||
sock_connected = modemGetConnected(); | |||
} | |||
return result; | |||
} | |||
bool modemGetConnected() { | |||
sendAT(F("+CIPSTATUS="), mux); | |||
int res = waitResponse(F(",\"CONNECTED\""), F(",\"CLOSED\""), F(",\"CLOSING\""), F(",\"INITIAL\"")); | |||
waitResponse(); | |||
return 1 == res; | |||
} | |||
/* Utilities */ | |||
template<typename T> | |||
void streamWrite(T last) { | |||
stream.print(last); | |||
} | |||
template<typename T, typename... Args> | |||
void streamWrite(T head, Args... tail) { | |||
stream.print(head); | |||
streamWrite(tail...); | |||
} | |||
int streamRead() { return stream.read(); } | |||
void streamReadAll() { while(stream.available()) { stream.read(); } } | |||
template<typename... Args> | |||
void sendAT(Args... cmd) { | |||
streamWrite("AT", cmd..., GSM_NL); | |||
} | |||
// TODO: Optimize this! | |||
uint8_t waitResponse(uint32_t timeout, String& data, | |||
GsmConstStr r1=FP(GSM_OK), GsmConstStr r2=FP(GSM_ERROR), | |||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | |||
{ | |||
data.reserve(64); | |||
bool gotNewData = false; | |||
int index = 0; | |||
for (unsigned long start = millis(); millis() - start < timeout; ) { | |||
while (stream.available() > 0) { | |||
int a = streamRead(); | |||
if (a < 0) continue; //? | |||
data += (char)a; | |||
if (data.indexOf(r1) >= 0) { | |||
index = 1; | |||
goto finish; | |||
} else if (r2 && data.indexOf(r2) >= 0) { | |||
index = 2; | |||
goto finish; | |||
} else if (r3 && data.indexOf(r3) >= 0) { | |||
index = 3; | |||
goto finish; | |||
} else if (r4 && data.indexOf(r4) >= 0) { | |||
index = 4; | |||
goto finish; | |||
} else if (r5 && data.indexOf(r5) >= 0) { | |||
index = 5; | |||
goto finish; | |||
} else if (data.indexOf(F(GSM_NL "+CIPRXGET: 1,1" GSM_NL)) >= 0) { //TODO: use mux | |||
gotNewData = true; | |||
data = ""; | |||
} else if (data.indexOf(F(GSM_NL "1, CLOSED" GSM_NL)) >= 0) { //TODO: use mux | |||
sock_connected = false; | |||
data = ""; | |||
} | |||
} | |||
} | |||
finish: | |||
if (!index) { | |||
if (data.length()) { | |||
DBG("### Unhandled:", data); | |||
} | |||
data = ""; | |||
} | |||
if (gotNewData) { | |||
sock_available = modemGetAvailable(); | |||
} | |||
return index; | |||
} | |||
uint8_t waitResponse(uint32_t timeout, | |||
GsmConstStr r1=FP(GSM_OK), GsmConstStr r2=FP(GSM_ERROR), | |||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | |||
{ | |||
String data; | |||
return waitResponse(timeout, data, r1, r2, r3, r4, r5); | |||
} | |||
uint8_t waitResponse(GsmConstStr r1=FP(GSM_OK), GsmConstStr r2=FP(GSM_ERROR), | |||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | |||
{ | |||
return waitResponse(1000, r1, r2, r3, r4, r5); | |||
} | |||
private: | |||
Stream& stream; | |||
const uint8_t mux; | |||
RxFifo rx; | |||
uint16_t sock_available; | |||
bool sock_connected; | |||
}; | |||
#endif |
@ -0,0 +1,136 @@ | |||
#ifndef TinyGsmFifo_h | |||
#define TinyGsmFifo_h | |||
template <class T, unsigned N> | |||
class TinyGsmFifo | |||
{ | |||
public: | |||
TinyGsmFifo() | |||
{ | |||
clear(); | |||
} | |||
void clear() | |||
{ | |||
_r = 0; | |||
_w = 0; | |||
} | |||
// writing thread/context API | |||
//------------------------------------------------------------- | |||
bool writeable(void) | |||
{ | |||
return free() > 0; | |||
} | |||
int free(void) | |||
{ | |||
int s = _r - _w; | |||
if (s <= 0) | |||
s += N; | |||
return s - 1; | |||
} | |||
T put(const T& c) | |||
{ | |||
int i = _w; | |||
int j = i; | |||
i = _inc(i); | |||
while (i == _r) // = !writeable() | |||
/* nothing / just wait */; | |||
_b[j] = c; | |||
_w = i; | |||
return c; | |||
} | |||
int put(const T* p, int n, bool t = false) | |||
{ | |||
int c = n; | |||
while (c) | |||
{ | |||
int f; | |||
while ((f = free()) == 0) // wait for space | |||
{ | |||
if (!t) return n - c; // no more space and not blocking | |||
/* nothing / just wait */; | |||
} | |||
// check free space | |||
if (c < f) f = c; | |||
int w = _w; | |||
int m = N - w; | |||
// check wrap | |||
if (f > m) f = m; | |||
memcpy(&_b[w], p, f); | |||
_w = _inc(w, f); | |||
c -= f; | |||
p += f; | |||
} | |||
return n - c; | |||
} | |||
// reading thread/context API | |||
// -------------------------------------------------------- | |||
bool readable(void) | |||
{ | |||
return (_r != _w); | |||
} | |||
size_t size(void) | |||
{ | |||
int s = _w - _r; | |||
if (s < 0) | |||
s += N; | |||
return s; | |||
} | |||
T get(void) | |||
{ | |||
int r = _r; | |||
while (r == _w) // = !readable() | |||
/* nothing / just wait */; | |||
T t = _b[r]; | |||
_r = _inc(r); | |||
return t; | |||
} | |||
int get(T* p, int n, bool t = false) | |||
{ | |||
int c = n; | |||
while (c) | |||
{ | |||
int f; | |||
for (;;) // wait for data | |||
{ | |||
f = size(); | |||
if (f) break; // free space | |||
if (!t) return n - c; // no space and not blocking | |||
/* nothing / just wait */; | |||
} | |||
// check available data | |||
if (c < f) f = c; | |||
int r = _r; | |||
int m = N - r; | |||
// check wrap | |||
if (f > m) f = m; | |||
memcpy(p, &_b[r], f); | |||
_r = _inc(r, f); | |||
c -= f; | |||
p += f; | |||
} | |||
return n - c; | |||
} | |||
private: | |||
int _inc(int i, int n = 1) | |||
{ | |||
return (i + n) % N; | |||
} | |||
T _b[N]; | |||
int _w; | |||
int _r; | |||
}; | |||
#endif |
@ -0,0 +1,75 @@ | |||
/************************************************************** | |||
* | |||
* For this example, you need to install Blynk library: | |||
* https://github.com/blynkkk/blynk-library/releases/latest | |||
* | |||
* TinyGSM Getting Started guide: | |||
* http://tiny.cc/tiny-gsm-readme | |||
* | |||
************************************************************** | |||
* | |||
* Blynk is a platform with iOS and Android apps to control | |||
* Arduino, Raspberry Pi and the likes over the Internet. | |||
* You can easily build graphic interfaces for all your | |||
* projects by simply dragging and dropping widgets. | |||
* | |||
* Blynk supports many development boards with WiFi, Ethernet, | |||
* GSM, Bluetooth, BLE, USB/Serial connection methods. | |||
* See more in Blynk library examples and community forum. | |||
* | |||
* http://www.blynk.io/ | |||
* | |||
* Change GPRS apm, user, pass, and Blynk auth token to run :) | |||
**************************************************************/ | |||
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space | |||
// Default heartbeat interval for GSM is 60 | |||
// If you want override this value, uncomment and set this option: | |||
//#define BLYNK_HEARTBEAT 30 | |||
#include <TinyGsmClient.h> | |||
#include <BlynkSimpleSIM800.h> | |||
// You should get Auth Token in the Blynk App. | |||
// Go to the Project Settings (nut icon). | |||
char auth[] = "YourAuthToken"; | |||
// Your GPRS credentials | |||
// Leave empty, if missing user or pass | |||
char apn[] = "YourAPN"; | |||
char user[] = ""; | |||
char pass[] = ""; | |||
// Hardware Serial on Mega, Leonardo, Micro | |||
#define GsmSerial Serial1 | |||
// or Software Serial on Uno, Nano | |||
//#include <SoftwareSerial.h> | |||
//SoftwareSerial GsmSerial(2, 3); // RX, TX | |||
TinyGsmClient gsm(GsmSerial); | |||
void setup() | |||
{ | |||
// Set console baud rate | |||
Serial.begin(115200); | |||
delay(10); | |||
// Set GSM module baud rate | |||
GsmSerial.begin(115200); | |||
delay(3000); | |||
// Restart takes quite some time | |||
// You can skip it in many cases | |||
Serial.println("Restarting modem..."); | |||
gsm.restart(); | |||
Blynk.begin(auth, gsm, apn, user, pass); | |||
} | |||
void loop() | |||
{ | |||
Blynk.run(); | |||
} | |||
@ -0,0 +1,153 @@ | |||
/************************************************************** | |||
* | |||
* For this example, you need to install CRC32 library: | |||
* https://github.com/vshymanskyy/CRC32.git | |||
* | |||
* TinyGSM Getting Started guide: | |||
* http://tiny.cc/tiny-gsm-readme | |||
* | |||
**************************************************************/ | |||
#include <TinyGsmClient.h> | |||
#include <CRC32.h> | |||
// Your GPRS credentials | |||
// Leave empty, if missing user or pass | |||
char apn[] = "YourAPN"; | |||
char user[] = ""; | |||
char pass[] = ""; | |||
// Use Hardware Serial on Mega, Leonardo, Micro | |||
#define GsmSerial Serial1 | |||
// or Software Serial on Uno, Nano | |||
//#include <SoftwareSerial.h> | |||
//SoftwareSerial GsmSerial(2, 3); // RX, TX | |||
TinyGsmClient client(GsmSerial); | |||
char server[] = "cdn.rawgit.com"; | |||
char resource[] = "/vshymanskyy/tinygsm/master/extras/test_10k.hex"; | |||
uint32_t knownCRC32 = 0x54b3dcbf; | |||
uint32_t knownFileSize = 10240; // In case server does not send it | |||
void setup() { | |||
// Set console baud rate | |||
Serial.begin(115200); | |||
delay(10); | |||
// Set GSM module baud rate | |||
GsmSerial.begin(115200); | |||
delay(3000); | |||
// Restart takes quite some time | |||
// You can skip it in many cases | |||
Serial.println("Restarting modem..."); | |||
client.restart(); | |||
} | |||
void printPercent(uint32_t readLength, uint32_t contentLength) { | |||
// If we know the total length | |||
if (contentLength != -1) { | |||
Serial.print(String("\r ") + ((100.0 * readLength) / contentLength) + "%"); | |||
} else { | |||
Serial.println(readLength); | |||
} | |||
} | |||
void loop() { | |||
Serial.print("Connecting to "); | |||
Serial.print(apn); | |||
if (!client.networkConnect(apn, user, pass)) { | |||
Serial.println(" failed"); | |||
delay(10000); | |||
return; | |||
} | |||
Serial.println(" OK"); | |||
Serial.print("Connecting to "); | |||
Serial.print(server); | |||
// if you get a connection, report back via serial: | |||
if (!client.connect(server, 80)) { | |||
Serial.println(" failed"); | |||
delay(10000); | |||
return; | |||
} | |||
Serial.println(" OK"); | |||
// Make a HTTP request: | |||
client.print(String("GET ") + resource + " HTTP/1.0\r\n"); | |||
client.print(String("Host: ") + server + "\r\n"); | |||
client.print("Connection: close\r\n\r\n"); | |||
long timeout = millis(); | |||
while (client.available() == 0) { | |||
if (millis() - timeout > 5000L) { | |||
Serial.println(">>> Client Timeout !"); | |||
client.stop(); | |||
delay(10000L); | |||
return; | |||
} | |||
} | |||
Serial.println("Reading response header"); | |||
uint32_t contentLength = knownFileSize; | |||
while (client.available()) { | |||
String line = client.readStringUntil('\n'); | |||
line.trim(); | |||
//Serial.println(line); // Uncomment this to show response header | |||
line.toLowerCase(); | |||
if (line.startsWith("content-length:")) { | |||
contentLength = line.substring(line.lastIndexOf(':') + 1).toInt(); | |||
} else if (line.length() == 0) { | |||
break; | |||
} | |||
} | |||
Serial.println("Reading response data"); | |||
timeout = millis(); | |||
uint32_t readLength = 0; | |||
CRC32 crc; | |||
unsigned long timeElapsed = millis(); | |||
printPercent(readLength, contentLength); | |||
while (readLength < contentLength && client.connected() && millis() - timeout < 10000L) { | |||
while (client.available()) { | |||
uint8_t c = client.read(); | |||
//Serial.print((char)c); // Uncomment this to show data | |||
crc.update(c); | |||
readLength++; | |||
if (readLength % (contentLength / 13) == 0) { | |||
printPercent(readLength, contentLength); | |||
} | |||
timeout = millis(); | |||
} | |||
} | |||
printPercent(readLength, contentLength); | |||
timeElapsed = millis() - timeElapsed; | |||
Serial.println(); | |||
client.stop(); | |||
Serial.println("Server disconnected"); | |||
client.networkDisconnect(); | |||
Serial.println("GPRS disconnected"); | |||
Serial.println(); | |||
float timeSpent = float(timeElapsed) / 1000; | |||
float theorLimit = ((8.0 * readLength) / 85.6) / 1000; | |||
Serial.print("Content-Length: "); Serial.println(contentLength); | |||
Serial.print("Actually read: "); Serial.println(readLength); | |||
Serial.print("Calc. CRC32: 0x"); Serial.println(crc.finalize(), HEX); | |||
Serial.print("Known CRC32: 0x"); Serial.println(knownCRC32, HEX); | |||
Serial.print("Time spent: "); Serial.print(timeSpent); Serial.println("s"); | |||
Serial.print("85.6kBps limit: "); Serial.print(theorLimit); Serial.println("s"); | |||
// Do nothing forevermore | |||
while (true) { | |||
delay(1000); | |||
} | |||
} | |||
@ -0,0 +1,130 @@ | |||
/************************************************************** | |||
* | |||
* For this example, you need to install PubSubClient library: | |||
* https://github.com/knolleary/pubsubclient/releases/latest | |||
* | |||
* TinyGSM Getting Started guide: | |||
* http://tiny.cc/tiny-gsm-readme | |||
* | |||
************************************************************** | |||
* Use Mosquitto client tools to work with MQTT | |||
* Ubuntu/Linux: sudo apt-get install mosquitto-clients | |||
* Windows: https://mosquitto.org/download/ | |||
* | |||
* Subscribe for messages: | |||
* mosquitto_sub -h test.mosquitto.org -t GsmClientTest/init -t GsmClientTest/ledStatus -q 1 | |||
* Toggle led: | |||
* mosquitto_pub -h test.mosquitto.org -t GsmClientTest/led -q 1 -m "toggle" | |||
* | |||
* You can use Node-RED for wiring together MQTT-enabled devices | |||
* https://nodered.org/ | |||
* Also, take a look at these additional Node-RED modules: | |||
* node-red-contrib-blynk-websockets | |||
* node-red-dashboard | |||
* | |||
**************************************************************/ | |||
#include <TinyGsmClient.h> | |||
#include <PubSubClient.h> | |||
// Your GPRS credentials | |||
// Leave empty, if missing user or pass | |||
char apn[] = "YourAPN"; | |||
char user[] = ""; | |||
char pass[] = ""; | |||
// Use Hardware Serial on Mega, Leonardo, Micro | |||
#define GsmSerial Serial1 | |||
// or Software Serial on Uno, Nano | |||
//#include <SoftwareSerial.h> | |||
//SoftwareSerial GsmSerial(2, 3); // RX, TX | |||
TinyGsmClient gsm(GsmSerial); | |||
PubSubClient mqtt(gsm); | |||
const char* broker = "test.mosquitto.org"; | |||
const char* topicLed = "GsmClientTest/led"; | |||
const char* topicInit = "GsmClientTest/init"; | |||
const char* topicLedStatus = "GsmClientTest/ledStatus"; | |||
#define LED_PIN 13 | |||
int ledStatus = LOW; | |||
long lastReconnectAttempt = 0; | |||
void setup() { | |||
pinMode(LED_PIN, OUTPUT); | |||
// Set console baud rate | |||
Serial.begin(115200); | |||
delay(10); | |||
// Set GSM module baud rate | |||
GsmSerial.begin(115200); | |||
delay(3000); | |||
// Restart takes quite some time | |||
// You can skip it in many cases | |||
Serial.println("Restarting modem..."); | |||
gsm.restart(); | |||
Serial.print("Connecting to "); | |||
Serial.print(apn); | |||
if (!gsm.networkConnect(apn, user, pass)) { | |||
Serial.println(" failed"); | |||
while (true); | |||
} | |||
Serial.println(" OK"); | |||
// MQTT Broker setup | |||
mqtt.setServer(broker, 1883); | |||
mqtt.setCallback(mqttCallback); | |||
} | |||
boolean mqttConnect() { | |||
Serial.print("Connecting to "); | |||
Serial.print(broker); | |||
if (!mqtt.connect("GsmClientTest")) { | |||
Serial.println(" failed"); | |||
return false; | |||
} | |||
Serial.println(" OK"); | |||
mqtt.publish(topicInit, "GsmClientTest started"); | |||
mqtt.subscribe(topicLed); | |||
return mqtt.connected(); | |||
} | |||
void loop() { | |||
if (mqtt.connected()) { | |||
mqtt.loop(); | |||
} else { | |||
// Reconnect every 10 seconds | |||
unsigned long t = millis(); | |||
if (t - lastReconnectAttempt > 10000L) { | |||
lastReconnectAttempt = t; | |||
if (mqttConnect()) { | |||
lastReconnectAttempt = 0; | |||
} | |||
} | |||
} | |||
} | |||
void mqttCallback(char* topic, byte* payload, unsigned int len) { | |||
Serial.print("Message arrived ["); | |||
Serial.print(topic); | |||
Serial.print("]: "); | |||
Serial.write(payload, len); | |||
Serial.println(); | |||
// Only proceed if incoming message's topic matches | |||
if (String(topic) == topicLed) { | |||
ledStatus = !ledStatus; | |||
digitalWrite(LED_PIN, ledStatus); | |||
mqtt.publish(topicLedStatus, ledStatus ? "1" : "0"); | |||
} | |||
} | |||
@ -0,0 +1,92 @@ | |||
/************************************************************** | |||
* | |||
* This sketch connects to a website and downloads a page. | |||
* It can be used to perform HTTP/RESTful API calls. | |||
* | |||
* TinyGSM Getting Started guide: | |||
* http://tiny.cc/tiny-gsm-readme | |||
* | |||
**************************************************************/ | |||
#include <TinyGsmClient.h> | |||
// Your GPRS credentials | |||
// Leave empty, if missing user or pass | |||
char apn[] = "YourAPN"; | |||
char user[] = ""; | |||
char pass[] = ""; | |||
// Use Hardware Serial on Mega, Leonardo, Micro | |||
#define GsmSerial Serial1 | |||
// or Software Serial on Uno, Nano | |||
//#include <SoftwareSerial.h> | |||
//SoftwareSerial GsmSerial(2, 3); // RX, TX | |||
TinyGsmClient client(GsmSerial); | |||
char server[] = "cdn.rawgit.com"; | |||
char resource[] = "/vshymanskyy/tinygsm/master/extras/logo.txt"; | |||
void setup() { | |||
// Set console baud rate | |||
Serial.begin(115200); | |||
delay(10); | |||
// Set GSM module baud rate | |||
GsmSerial.begin(115200); | |||
delay(3000); | |||
// Restart takes quite some time | |||
// You can skip it in many cases | |||
Serial.println("Restarting modem..."); | |||
client.restart(); | |||
} | |||
void loop() { | |||
Serial.print("Connecting to "); | |||
Serial.print(apn); | |||
if (!client.networkConnect(apn, user, pass)) { | |||
Serial.println(" failed"); | |||
delay(10000); | |||
return; | |||
} | |||
Serial.println(" OK"); | |||
Serial.print("Connecting to "); | |||
Serial.print(server); | |||
if (!client.connect(server, 80)) { | |||
Serial.println(" failed"); | |||
delay(10000); | |||
return; | |||
} | |||
Serial.println(" OK"); | |||
// Make a HTTP GET request: | |||
client.print(String("GET ") + resource + " HTTP/1.0\r\n"); | |||
client.print(String("Host: ") + server + "\r\n"); | |||
client.print("Connection: close\r\n\r\n"); | |||
unsigned long timeout = millis(); | |||
while (client.connected() && millis() - timeout < 10000L) { | |||
// Print available data | |||
while (client.available()) { | |||
char c = client.read(); | |||
Serial.print(c); | |||
timeout = millis(); | |||
} | |||
} | |||
Serial.println(); | |||
client.stop(); | |||
Serial.println("Server disconnected"); | |||
client.networkDisconnect(); | |||
Serial.println("GPRS disconnected"); | |||
// Do nothing forevermore | |||
while (true) { | |||
delay(1000); | |||
} | |||
} | |||