A6 A7 gateway (GSM GPRS) (#195)

* init 2G gateway with SMS sending and receiving

* A6lib add

* add 2Ggateway call from setup and loop

* add schematic and image
This commit is contained in:
Florian authored and GitHub committed 2018-04-21 19:22:36 +02:00
1 parent 0412461d66
commit 513d71c544
18 files changed
+1382

No files matched your search

+33
View File
@@ -73,6 +73,9 @@
#ifdef ZgatewayIR
#include "config_IR.h"
#endif
#ifdef Zgateway2G
#include "config_2G.h"
#endif
#ifdef ZactuatorONOFF
#include "config_ONOFF.h"
#endif
@@ -329,6 +332,9 @@ void setup()
#ifdef ZactuatorONOFF
setupONOFF();
#endif
#ifdef Zgateway2G
setup2G();
#endif
#ifdef ZgatewayIR
setupIR();
#endif
@@ -625,6 +631,11 @@ void loop()
trc(F("BTtoMQTT OK"));
#endif
#endif
#ifdef Zgateway2G
if(_2GtoMQTT()){
trc(F("2GtoMQTT OK"));
}
#endif
#ifdef ZgatewayRFM69
if(RFM69toMQTT())
trc(F("RFM69toMQTT OK"));
@@ -705,6 +716,9 @@ digitalWrite(led_send, LOW);
#ifdef ZgatewayRF2
MQTTtoRF2(topicOri, datacallback);
#endif
#ifdef Zgateway2G
MQTTto2G(topicOri, datacallback);
#endif
#ifdef ZgatewaySRFB
MQTTtoSRFB(topicOri, datacallback);
#endif
@@ -761,3 +775,22 @@ void trc(String msg){
Serial.println(msg);
}
}
void trc(int msg){
if (TRACE) {
Serial.println(msg);
}
}
void trc(uint32_t msg){
if (TRACE) {
Serial.println(msg);
}
}
void trc(float msg){
if (TRACE) {
Serial.println(msg);
}
}
+133
View File
@@ -0,0 +1,133 @@
/*
OpenMQTTGateway - ESP8266 or Arduino program for home automation
Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal and a MQTT broker
Send and receiving command by MQTT
This gateway enables to:
- receive MQTT data from a topic and send SMS corresponding to the received MQTT data
- publish MQTT data to a different topic related to received SMS
Copyright: (c)Florian ROBERT
This file is part of OpenMQTTGateway.
OpenMQTTGateway is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenMQTTGateway is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef Zgateway2G
#include <A6lib.h> // library for controling A6 or A7 module
// Instantiate the library with TxPin, RxPin.
A6lib A6l(_2G_TX_PIN, _2G_RX_PIN); //D6 to A6 RX, D7 to A6 TX
int unreadSMSLocs[50] = {0};
int unreadSMSNum = 0;
SMSmessage sms;
void setup2G(){
trc(F("_2G_TX_PIN "));
trc(String(_2G_TX_PIN));
trc(F("_2G_RX_PIN "));
trc(String(_2G_RX_PIN));
setupGSM(false);
trc(F("Zgateway2G setup done "));
}
void setupGSM(boolean deleteSMS){
trc("Init 2G module: ");
trc(_2G_PWR_PIN);
delay(1000);
// Power-cycle the module to reset it.
A6l.powerCycle(_2G_PWR_PIN);
trc("waiting for network connection");
A6l.blockUntilReady(_2G_MODULE_BAUDRATE);
trc("A6/A7 gsm ready");
signalStrengthAnalysis();
delay(1000);
// deleting all sms
if (deleteSMS){
if (A6l.deleteSMS(1,4) == A6_OK ) {
trc("delete SMS OK");
}else{
trc("delete SMS KO");
}
}
}
void signalStrengthAnalysis(){
int signalStrength = 0;
signalStrength = A6l.getSignalStrength();
trc("Signal strength: ");
trc(signalStrength);
if (signalStrength < _2G_MIN_SIGNAL || signalStrength > _2G_MAX_SIGNAL ) {
trc("Signal too low restart the module");
setupGSM(false); // if we are below or above a threshold signal we relaunch the setup of GSM module
}
}
boolean _2GtoMQTT(){
// Get the memory locations of unread SMS messages.
unreadSMSNum = A6l.getUnreadSMSLocs(unreadSMSLocs, 512);
for (int i = 0; i < unreadSMSNum; i++) {
trc("New message at index: ");
trc(unreadSMSNum);
sms = A6l.readSMS(unreadSMSLocs[i]);
trc(sms.number);
trc(sms.date);
trc(sms.message);
A6l.deleteSMS(unreadSMSLocs[i]); // we delete the SMS received
trc(F("data 2GtoMQTT"));
client.publish(subject2GtoMQTTphone,(char *)sms.number.c_str());
client.publish(subject2GtoMQTTdate,(char *)sms.date.c_str());
client.publish(subject2GtoMQTTmessage,(char *)sms.message.c_str());
return true;
}
return false;
}
void MQTTto2G(char * topicOri, char * datacallback) {
String data = datacallback; // we will not be able to pass values > 4294967295
// 2G DATA ANALYSIS
//We look into the subject to see if a special RF protocol is defined
String topic = topicOri;
String phone_number = "";
int pos0 = topic.lastIndexOf(_2GPhoneKey);
if (pos0 != -1) {
pos0 = pos0 + strlen(_2GPhoneKey);
phone_number = topic.substring(pos0);
trc(F("Phone number to send SMS:"));
trc(phone_number);
}
if((strstr(topicOri, subjectMQTTto2G) != NULL) && (pos0 != -1)){
trc(F("MQTTto2G"));
trc(data);
if (A6l.sendSMS(phone_number,data) == A6_OK ) {
trc("SMS OK");
}else{
trc("SMS KO");
}
// Acknowledgement to the GTW2G topic
boolean result = client.publish(subjectGTW2GtoMQTT, datacallback);// we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also
if (result){
trc(F("MQTTto2G ack pub."));
trc(String(data));
}
}
}
#endif
+46
View File
@@ -0,0 +1,46 @@
/*
OpenMQTTGateway - ESP8266 or Arduino program for home automation
Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal and a MQTT broker
Send and receiving command by MQTT
This gateway enables to set your parameters for the 2G gateway
Copyright: (c)Florian ROBERT
This file is part of OpenMQTTGateway.
OpenMQTTGateway is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenMQTTGateway is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*-------------------2G topics & parameters----------------------*/
//433Mhz MQTT Subjects and keys
#define subjectMQTTto2G Base_Topic Gateway_Name "/commands/MQTTto2G"
#define subject2GtoMQTT Base_Topic Gateway_Name "/2GtoMQTT"
#define subjectGTW2GtoMQTT Base_Topic Gateway_Name "/2GtoMQTT"
#define subject2GtoMQTTphone Base_Topic Gateway_Name "/2GtoMQTT/phone"
#define subject2GtoMQTTdate Base_Topic Gateway_Name "/2GtoMQTT/date"
#define subject2GtoMQTTmessage Base_Topic Gateway_Name "/2GtoMQTT/message"
#define _2GPhoneKey "PHO_" // phone number define the phone number to send the SMS MQTT->2G
#define _2G_MODULE_BAUDRATE 9600
#define _2G_MIN_SIGNAL 30
#define _2G_MAX_SIGNAL 1000
/*-------------------PIN DEFINITIONS----------------------*/
#define _2G_TX_PIN D6 //D6 to A6 RX,
#define _2G_RX_PIN D7 //D7 to A6 TX
#define _2G_PWR_PIN D5
#define _2G_RST_PIN D0
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

+21
View File
@@ -0,0 +1,21 @@
# EditorConfig file: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = false
# 4 space indentation
[*.{cpp,h}]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
# 2 space indentation
[*.json]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
+504
View File
@@ -0,0 +1,504 @@
#include <Arduino.h>
#include <SoftwareSerial.h>
#include "A6lib.h"
/////////////////////////////////////////////
// Public methods.
//
A6lib::A6lib(int transmitPin, int receivePin) {
#ifdef ESP8266
A6conn = new SoftwareSerial(receivePin, transmitPin, false, 1024);
#else
A6conn = new SoftwareSerial(receivePin, transmitPin, false);
#endif
A6conn->setTimeout(100);
}
A6lib::~A6lib() {
delete A6conn;
}
// Block until the module is ready.
byte A6lib::blockUntilReady(long baudRate) {
byte response = A6_NOTOK;
while (A6_OK != response) {
response = begin(baudRate);
// This means the modem has failed to initialize and we need to reboot
// it.
if (A6_FAILURE == response) {
return A6_FAILURE;
}
delay(1000);
logln("Waiting for module to be ready...");
}
return A6_OK;
}
// Initialize the software serial connection and change the baud rate from the
// default (autodetected) to the desired speed.
byte A6lib::begin(long baudRate) {
A6conn->flush();
if (A6_OK != setRate(baudRate)) {
return A6_NOTOK;
}
// Factory reset.
A6command("AT&F", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
// Echo off.
A6command("ATE0", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
// Switch audio to headset.
enableSpeaker(0);
// Set caller ID on.
A6command("AT+CLIP=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
// Set SMS to text mode.
A6command("AT+CMGF=1", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
// Turn SMS indicators off.
A6command("AT+CNMI=1,0", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
// Set SMS storage to the GSM modem.
if (A6_OK != A6command("AT+CPMS=SM,ME,SM", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL))
// This may sometimes fail, in which case the modem needs to be
// rebooted.
{
return A6_FAILURE;
}
// Set SMS character set.
setSMScharset("UCS2");
return A6_OK;
}
// Reboot the module by setting the specified pin HIGH, then LOW. The pin should
// be connected to a P-MOSFET, not the A6's POWER pin.
void A6lib::powerCycle(int pin) {
logln("Power-cycling module...");
powerOff(pin);
delay(2000);
powerOn(pin);
delay(4000);
powerOff(pin);
// Give the module some time to settle.
logln("Done, waiting for the module to initialize...");
delay(20000);
logln("Done.");
A6conn->flush();
}
// Turn the modem power completely off.
void A6lib::powerOff(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
// Turn the modem power on.
void A6lib::powerOn(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
}
// Dial a number.
void A6lib::dial(String number) {
char buffer[50];
logln("Dialing number...");
sprintf(buffer, "ATD%s;", number.c_str());
A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
// Redial the last number.
void A6lib::redial() {
logln("Redialing last number...");
A6command("AT+DLST", "OK", "CONNECT", A6_CMD_TIMEOUT, 2, NULL);
}
// Answer a call.
void A6lib::answer() {
A6command("ATA", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
// Hang up the phone.
void A6lib::hangUp() {
A6command("ATH", "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
// Check whether there is an active call.
callInfo A6lib::checkCallStatus() {
char number[50];
String response = "";
uint32_t respStart = 0, matched = 0;
callInfo cinfo = (const struct callInfo) {
0
};
// Issue the command and wait for the response.
A6command("AT+CLCC", "OK", "+CLCC", A6_CMD_TIMEOUT, 2, &response);
// Parse the response if it contains a valid +CLCC.
respStart = response.indexOf("+CLCC");
if (respStart >= 0) {
matched = sscanf(response.substring(respStart).c_str(), "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d", &cinfo.index, &cinfo.direction, &cinfo.state, &cinfo.mode, &cinfo.multiparty, number, &cinfo.type);
cinfo.number = String(number);
}
uint8_t comma_index = cinfo.number.indexOf('"');
if (comma_index != -1) {
logln("Extra comma found.");
cinfo.number = cinfo.number.substring(0, comma_index);
}
return cinfo;
}
// Get the strength of the GSM signal.
int A6lib::getSignalStrength() {
String response = "";
uint32_t respStart = 0;
int strength, error = 0;
// Issue the command and wait for the response.
A6command("AT+CSQ", "OK", "+CSQ", A6_CMD_TIMEOUT, 2, &response);
respStart = response.indexOf("+CSQ");
if (respStart < 0) {
return 0;
}
sscanf(response.substring(respStart).c_str(), "+CSQ: %d,%d",
&strength, &error);
// Bring value range 0..31 to 0..100%, don't mind rounding..
strength = (strength * 100) / 31;
return strength;
}
// Get the real time from the modem. Time will be returned as yy/MM/dd,hh:mm:ss+XX
String A6lib::getRealTimeClock() {
String response = "";
// Issue the command and wait for the response.
A6command("AT+CCLK?", "OK", "yy", A6_CMD_TIMEOUT, 1, &response);
int respStart = response.indexOf("+CCLK: \"") + 8;
response.setCharAt(respStart - 1, '-');
return response.substring(respStart, response.indexOf("\""));
}
// Send an SMS.
byte A6lib::sendSMS(String number, String text) {
char ctrlZ[2] = { 0x1a, 0x00 };
char buffer[100];
if (text.length() > 159) {
// We can't send messages longer than 160 characters.
return A6_NOTOK;
}
log("Sending SMS to ");
log(number);
logln("...");
sprintf(buffer, "AT+CMGS=\"%s\"", number.c_str());
A6command(buffer, ">", "yy", A6_CMD_TIMEOUT, 2, NULL);
delay(100);
A6conn->println(text.c_str());
A6conn->println(ctrlZ);
A6conn->println();
return A6_OK;
}
// Retrieve the number and locations of unread SMS messages.
int A6lib::getUnreadSMSLocs(int* buf, int maxItems) {
return getSMSLocsOfType(buf, maxItems, "REC UNREAD");
}
// Retrieve the number and locations of all SMS messages.
int A6lib::getSMSLocs(int* buf, int maxItems) {
return getSMSLocsOfType(buf, maxItems, "ALL");
}
// Retrieve the number and locations of all SMS messages.
int A6lib::getSMSLocsOfType(int* buf, int maxItems, String type) {
String seqStart = "+CMGL: ";
String response = "";
String command = "AT+CMGL=\"";
command += type;
command += "\"";
// Issue the command and wait for the response.
byte status = A6command(command.c_str(), "\xff\r\nOK\r\n", "\r\nOK\r\n", A6_CMD_TIMEOUT, 2, &response);
int seqStartLen = seqStart.length();
int responseLen = response.length();
int index, occurrences = 0;
// Start looking for the +CMGL string.
for (int i = 0; i < (responseLen - seqStartLen); i++) {
// If we found a response and it's less than occurrences, add it.
if (response.substring(i, i + seqStartLen) == seqStart && occurrences < maxItems) {
// Parse the position out of the reply.
sscanf(response.substring(i, i + 12).c_str(), "+CMGL: %u,%*s", &index);
buf[occurrences] = index;
occurrences++;
}
}
return occurrences;
}
// Return the SMS at index.
SMSmessage A6lib::readSMS(int index) {
String response = "";
char buffer[30];
// Issue the command and wait for the response.
sprintf(buffer, "AT+CMGR=%d", index);
A6command(buffer, "\xff\r\nOK\r\n", "\r\nOK\r\n", A6_CMD_TIMEOUT, 2, &response);
char message[200];
char number[50];
char date[50];
char type[10];
int respStart = 0, matched = 0;
SMSmessage sms = (const struct SMSmessage) {
"", "", ""
};
// Parse the response if it contains a valid +CLCC.
respStart = response.indexOf("+CMGR");
if (respStart >= 0) {
// Parse the message header.
matched = sscanf(response.substring(respStart).c_str(), "+CMGR: \"REC %s\",\"%s\",,\"%s\"\r\n", type, number, date);
sms.number = String(number);
sms.date = String(date);
// The rest is the message, extract it.
sms.message = response.substring(strlen(type) + strlen(number) + strlen(date) + 24, response.length() - 8);
}
return sms;
}
// Delete the SMS at index.
byte A6lib::deleteSMS(int index) {
char buffer[20];
sprintf(buffer, "AT+CMGD=%d", index);
return A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
// Delete SMS with special flags
byte A6lib::deleteSMS(int index, int flag) {
char buffer[20];
String command = "AT+CMGD=";
command += String(index);
command += ",";
command += String(flag);
return A6command(command.c_str(), "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
} // AT+CMGD=1,4 delete all SMS from the storage area
// Set the SMS charset.
byte A6lib::setSMScharset(String charset) {
char buffer[30];
sprintf(buffer, "AT+CSCS=\"%s\"", charset.c_str());
return A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
// Set the volume for the speaker. level should be a number between 5 and
// 8 inclusive.
void A6lib::setVol(byte level) {
char buffer[30];
// level should be between 5 and 8.
level = _min(_max(level, 5), 8);
sprintf(buffer, "AT+CLVL=%d", level);
A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
// Enable the speaker, rather than the headphones. Pass 0 to route audio through
// headphones, 1 through speaker.
void A6lib::enableSpeaker(byte enable) {
char buffer[30];
// enable should be between 0 and 1.
enable = _min(_max(enable, 0), 1);
sprintf(buffer, "AT+SNFS=%d", enable);
A6command(buffer, "OK", "yy", A6_CMD_TIMEOUT, 2, NULL);
}
/////////////////////////////////////////////
// Private methods.
//
// Autodetect the connection rate.
long A6lib::detectRate() {
unsigned long rate = 0;
unsigned long rates[] = {9600, 115200};
// Try to autodetect the rate.
logln("Autodetecting connection rate...");
for (int i = 0; i < countof(rates); i++) {
rate = rates[i];
A6conn->begin(rate);
log("Trying rate ");
log(rate);
logln("...");
delay(100);
if (A6command("\rAT", "OK", "+CME", 2000, 2, NULL) == A6_OK) {
return rate;
}
}
logln("Couldn't detect the rate.");
return A6_NOTOK;
}
// Set the A6 baud rate.
char A6lib::setRate(long baudRate) {
int rate = 0;
rate = detectRate();
if (rate == A6_NOTOK) {
return A6_NOTOK;
}
// The rate is already the desired rate, return.
//if (rate == baudRate) return OK;
logln("Setting baud rate on the module...");
// Change the rate to the requested.
char buffer[30];
sprintf(buffer, "AT+IPR=%d", baudRate);
A6command(buffer, "OK", "+IPR=", A6_CMD_TIMEOUT, 3, NULL);
logln("Switching to the new rate...");
// Begin the connection again at the requested rate.
A6conn->begin(baudRate);
logln("Rate set.");
return A6_OK;
}
// Read some data from the A6 in a non-blocking manner.
String A6lib::read() {
String reply = "";
if (A6conn->available()) {
reply = A6conn->readString();
}
// XXX: Replace NULs with \xff so we can match on them.
for (int x = 0; x < reply.length(); x++) {
if (reply.charAt(x) == 0) {
reply.setCharAt(x, 255);
}
}
return reply;
}
// Issue a command.
byte A6lib::A6command(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response) {
byte returnValue = A6_NOTOK;
byte count = 0;
// Get rid of any buffered output.
A6conn->flush();
while (count < repetitions && returnValue != A6_OK) {
log("Issuing command: ");
logln(command);
A6conn->write(command);
A6conn->write('\r');
if (A6waitFor(resp1, resp2, timeout, response) == A6_OK) {
returnValue = A6_OK;
} else {
returnValue = A6_NOTOK;
}
count++;
}
return returnValue;
}
// Wait for responses.
byte A6lib::A6waitFor(const char *resp1, const char *resp2, int timeout, String *response) {
unsigned long entry = millis();
int count = 0;
String reply = "";
byte retVal = 99;
do {
reply += read();
#ifdef ESP8266
yield();
#endif
} while (((reply.indexOf(resp1) + reply.indexOf(resp2)) == -2) && ((millis() - entry) < timeout));
if (reply != "") {
log("Reply in ");
log((millis() - entry));
log(" ms: ");
logln(reply);
}
if (response != NULL) {
*response = reply;
}
if ((millis() - entry) >= timeout) {
retVal = A6_TIMEOUT;
logln("Timed out.");
} else {
if (reply.indexOf(resp1) + reply.indexOf(resp2) > -2) {
logln("Reply OK.");
retVal = A6_OK;
} else {
logln("Reply NOT OK.");
retVal = A6_NOTOK;
}
}
return retVal;
}
+111
View File
@@ -0,0 +1,111 @@
#ifndef A6lib_h
#define A6lib_h
#include <Arduino.h>
#include "SoftwareSerial.h"
#ifdef DEBUG
#define log(msg) Serial.print(msg)
#define logln(msg) Serial.println(msg)
#else
#define log(msg)
#define logln(msg)
#endif
#define countof(a) (sizeof(a) / sizeof(a[0]))
#define A6_OK 0
#define A6_NOTOK 1
#define A6_TIMEOUT 2
#define A6_FAILURE 3
#define A6_CMD_TIMEOUT 5000
enum call_direction {
DIR_OUTGOING = 0,
DIR_INCOMING = 1
};
enum call_state {
CALL_ACTIVE = 0,
CALL_HELD = 1,
CALL_DIALING = 2,
CALL_ALERTING = 3,
CALL_INCOMING = 4,
CALL_WAITING = 5,
CALL_RELEASE = 7
};
enum call_mode {
MODE_VOICE = 0,
MODE_DATA = 1,
MODE_FAX = 2,
MODE_VOICE_THEN_DATA_VMODE = 3,
MODE_VOICE_AND_DATA_VMODE = 4,
MODE_VOICE_AND_FAX_VMODE = 5,
MODE_VOICE_THEN_DATA_DMODE = 6,
MODE_VOICE_AND_DATA_DMODE = 7,
MODE_VOICE_AND_FAX_FMODE = 8,
MODE_UNKNOWN = 9
};
struct SMSmessage {
String number;
String date;
String message;
};
struct callInfo {
int index;
call_direction direction;
call_state state;
call_mode mode;
int multiparty;
String number;
int type;
};
class A6lib {
public:
A6lib(int transmitPin, int receivePin);
~A6lib();
byte begin(long baudRate);
byte blockUntilReady(long baudRate);
void powerCycle(int pin);
void powerOn(int pin);
void powerOff(int pin);
void dial(String number);
void redial();
void answer();
void hangUp();
callInfo checkCallStatus();
int getSignalStrength();
byte sendSMS(String number, String text);
int getUnreadSMSLocs(int* buf, int maxItems);
int getSMSLocs(int* buf, int maxItems);
int getSMSLocsOfType(int* buf, int maxItems, String type);
SMSmessage readSMS(int index);
byte deleteSMS(int index);
byte deleteSMS(int index, int flag);
byte setSMScharset(String charset);
void setVol(byte level);
void enableSpeaker(byte enable);
String getRealTimeClock();
SoftwareSerial *A6conn;
private:
String read();
byte A6command(const char *command, const char *resp1, const char *resp2, int timeout, int repetitions, String *response);
byte A6waitFor(const char *resp1, const char *resp2, int timeout, String *response);
long detectRate();
char setRate(long baudRate);
};
#endif
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Stavros Korokithakis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+65
View File
@@ -0,0 +1,65 @@
# A6lib
An ESP8266/Arduino library for communicating with the AI-Thinker A6 GSM module.
It will probably also work with other GSM modules that use the AT command set,
like the SIM900.
## Details
This library is an adaptation of
[this sample module](https://github.com/SensorsIot/A6-GSM-Module). It is still
very incomplete, but at least it works somewhat. Please feel free to issue pull
requests to improve it.
## Usage
If you have the A6 breakout board, connect the Tx and Rx pins to your ESP8266.
The example assumes the TX pin is connected to D5 and the RX to D6. A6lib can
power-cycle the module if you connect a MOSFET to a pin and control the A6's
power supply with it.
For a sample circuit that uses this library, have a look at [the A6/ESP8266
breakout board](https://gitlab.com/stavros/A6-ESP8266-breakout/) I designed.
The A6's PWR pin should be permanently connected to Vcc (if you think that's
wrong or know a better way, please open an issue).
The code looks something like this:
~~~
// Instantiate the class with Tx, Rx (remember to swap them when connecting to
the A6, i.e. connect the A6's Rx pin to D6).
A6lib A6c(D6, D5);
// Initialize the modem, rebooting it if it fails to become ready.
do {
// Power-cycle the module to reset it.
A6c.powerCycle(D0);
} while (A6c.blockUntilReady(9600) != A6_OK);
// Start and place a call.
A6c.dial("1234567890");
delay(8000);
A6c.hangUp();
delay(8000);
A6c.redial();
delay(8000);
// Send a message.
A6c.sendSMS("+1234567890", "Hello there!");
// Get an SMS message from memory.
SMSmessage sms = A6c.readSMS(3);
// Delete an SMS message.
A6c.deleteSMS(3);
callInfo cinfo = A6c.checkCallStatus();
// This will be the calling number, "1234567890".
cinfo.number;
~~~
This library doesn't currently include any code to connect to the internet, but
a PR adding that would be very welcome.
+44
View File
@@ -0,0 +1,44 @@
#include <A6lib.h>
#ifndef ESP8266
#define D0 0
#define D5 8
#define D6 7
#endif
// Instantiate the library with TxPin, RxPin.
A6lib A6l(D6, D5);
void setup() {
Serial.begin(115200);
delay(1000);
// Power-cycle the module to reset it.
A6l.powerCycle(D0);
A6l.blockUntilReady(9600);
}
void loop() {
Serial.println("Checking call status...");
callInfo cinfo = A6l.checkCallStatus();
Serial.println("Call status checked.");
int sigStrength = A6l.getSignalStrength();
Serial.print("Signal strength percentage: ");
Serial.println(sigStrength);
delay(5000);
if (cinfo.number != NULL) {
if (cinfo.direction == DIR_INCOMING && cinfo.number == "919999999999") {
A6l.answer();
} else {
A6l.hangUp();
}
delay(1000);
} else {
Serial.println("No number yet.");
delay(1000);
}
}
@@ -0,0 +1,30 @@
#include <A6lib.h>
#ifndef ESP8266
#define D0 0
#define D5 8
#define D6 7
#endif
// Instantiate the library with TxPin, RxPin.
A6lib A6l(D6, D5);
void setup() {
Serial.begin(115200);
delay(1000);
// Power-cycle the module to reset it.
A6l.powerCycle(D0);
A6l.blockUntilReady(9600);
}
void loop() {
// Relay things between Serial and the module's SoftSerial.
while (A6l.A6conn->available() > 0) {
Serial.write(A6l.A6conn->read());
}
while (Serial.available() > 0) {
A6l.A6conn->write(Serial.read());
}
}
+51
View File
@@ -0,0 +1,51 @@
#include <A6lib.h>
#ifdef ESP8266
#define D0 0
#define D5 8
#define D6 7
#endif
// Instantiate the library with TxPin, RxPin.
A6lib A6l(D6, D5);
int unreadSMSLocs[30] = {0};
int unreadSMSNum = 0;
SMSmessage sms;
void setup() {
Serial.begin(115200);
delay(1000);
// Power-cycle the module to reset it.
A6l.powerCycle(D0);
A6l.blockUntilReady(9600);
}
void loop() {
String myNumber = "+1132352890";
callInfo cinfo = A6l.checkCallStatus();
if (cinfo.direction == DIR_INCOMING) {
if (myNumber.endsWith(cinfo.number)) {
// If the number that sent the SMS is ours, reply.
A6l.sendSMS(myNumber, "I can't come to the phone right now, I'm a machine.");
A6l.hangUp();
}
// Get the memory locations of unread SMS messages.
unreadSMSNum = A6l.getUnreadSMSLocs(unreadSMSLocs, 30);
for (int i = 0; i < unreadSMSNum; i++) {
Serial.print("New message at index: ");
Serial.println(unreadSMSLocs[i], DEC);
sms = A6l.readSMS(unreadSMSLocs[i]);
Serial.println(sms.number);
Serial.println(sms.date);
Serial.println(sms.message);
}
delay(1000);
}
}
+35
View File
@@ -0,0 +1,35 @@
#######################################
# A6 GSM communication module
# (esp8266)
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
A6lib KEYWORD1
callInfo KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
powerCycle KEYWORD2
dial KEYWORD2
redial KEYWORD2
hangUp KEYWORD2
checkCallStatus KEYWORD2
getSignalStrength KEYWORD2
sendSMS KEYWORD2
setVol KEYWORD2
enableSpeaker KEYWORD2
A6conn KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+14
View File
@@ -0,0 +1,14 @@
{
"name": "A6lib",
"keywords": [
"A6", "GSM", "mobile"
],
"description": "An ESP8266/Arduino library for communicating with the A6 GSM module.",
"repository":
{
"type": "git",
"url": "https://github.com/skorokithakis/A6lib"
},
"frameworks": "arduino",
"platforms": "*"
}
+9
View File
@@ -0,0 +1,9 @@
name=A6lib
version=0.1.3
author=Stavros Korokithakis
maintainer=Stavros Korokithakis (hi@stavros.io)
sentence=An ESP8266/Arduino library for communicating with the A6 GSM module.
paragraph=
category=Communication
url=https://github.com/skorokithakis/A6lib
architectures=*
+262
View File
@@ -0,0 +1,262 @@
/*
* Copyright (c) 2000-2002 Opsycon AB (www.opsycon.se)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Opsycon AB.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#define MAXLN 200
#define ISSPACE " \t\n\r\f\v\""
size_t strcspn(const char *p, const char *s) {
int i, j;
for (i = 0; p[i]; i++) {
for (j = 0; s[j]; j++) {
if (s[j] == p[i]) {
break;
}
}
if (s[j]) {
break;
}
}
return (i);
}
char * _getbase(char *p, int *basep) {
if (p[0] == '0') {
switch (p[1]) {
case 'x':
*basep = 16;
break;
case 't':
case 'n':
*basep = 10;
break;
case 'o':
*basep = 8;
break;
default:
*basep = 10;
return (p);
}
return (p + 2);
}
*basep = 10;
return (p);
}
/*
* _atob(vp,p,base)
*/
int _atob(uint32_t *vp, char *p, int base) {
uint32_t value, v1, v2;
char *q, tmp[20];
int digit;
if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
base = 16;
p += 2;
}
if (base == 16 && (q = strchr(p, '.')) != 0) {
if (q - p > sizeof(tmp) - 1) {
return (0);
}
strncpy(tmp, p, q - p);
tmp[q - p] = '\0';
if (!_atob(&v1, tmp, 16)) {
return (0);
}
q++;
if (strchr(q, '.')) {
return (0);
}
if (!_atob(&v2, q, 16)) {
return (0);
}
*vp = (v1 << 16) + v2;
return (1);
}
value = *vp = 0;
for (; *p; p++) {
if (*p >= '0' && *p <= '9') {
digit = *p - '0';
} else if (*p >= 'a' && *p <= 'f') {
digit = *p - 'a' + 10;
} else if (*p >= 'A' && *p <= 'F') {
digit = *p - 'A' + 10;
} else {
return (0);
}
if (digit >= base) {
return (0);
}
value *= base;
value += digit;
}
*vp = value;
return (1);
}
/*
* atob(vp,p,base)
* converts p to binary result in vp, rtn 1 on success
*/
int atob(uint32_t *vp, char *p, int base) {
uint32_t v;
if (base == 0) {
p = _getbase(p, &base);
}
if (_atob(&v, p, base)) {
*vp = v;
return (1);
}
return (0);
}
/*
* vsscanf(buf,fmt,ap)
*/
int vsscanf(const char *buf, const char *s, va_list ap) {
uint32_t count, noassign, width, base, lflag;
const char *tc;
char *t, tmp[MAXLN];
count = noassign = width = lflag = 0;
while (*s && *buf) {
while (isspace(*s)) {
s++;
}
if (*s == '%') {
s++;
for (; *s; s++) {
if (strchr("dibouxcsefg%", *s)) {
break;
}
if (*s == '*') {
noassign = 1;
} else if (*s == 'l' || *s == 'L') {
lflag = 1;
} else if (*s >= '1' && *s <= '9') {
for (tc = s; isdigit(*s); s++);
strncpy(tmp, tc, s - tc);
tmp[s - tc] = '\0';
atob(&width, tmp, 10);
s--;
}
}
if (*s == 's') {
while (isspace(*buf)) {
buf++;
}
if (!width) {
width = strcspn(buf, ISSPACE);
}
if (!noassign) {
strncpy(t = va_arg(ap, char *), buf, width);
t[width] = '\0';
}
buf += width;
} else if (*s == 'c') {
if (!width) {
width = 1;
}
if (!noassign) {
strncpy(t = va_arg(ap, char *), buf, width);
t[width] = '\0';
}
buf += width;
} else if (strchr("dobxu", *s)) {
while (isspace(*buf)) {
buf++;
}
if (*s == 'd' || *s == 'u') {
base = 10;
} else if (*s == 'x') {
base = 16;
} else if (*s == 'o') {
base = 8;
} else if (*s == 'b') {
base = 2;
}
if (!width) {
if (isspace(*(s + 1)) || *(s + 1) == 0) {
width = strcspn(buf, ISSPACE);
} else {
width = strchr(buf, *(s + 1)) - buf;
}
}
strncpy(tmp, buf, width);
tmp[width] = '\0';
buf += width;
if (!noassign) {
atob(va_arg(ap, uint32_t *), tmp, base);
}
}
if (!noassign) {
count++;
}
width = noassign = lflag = 0;
s++;
} else {
while (isspace(*buf)) {
buf++;
}
if (*s != *buf) {
break;
} else {
s++, buf++;
}
}
}
return (count);
}
int __attribute__((used)) sscanf(const char *buf, const char *fmt, ...) {
int count;
va_list ap;
va_start(ap, fmt);
count = vsscanf(buf, fmt, ap);
va_end(ap);
return (count);
}
+3
View File
@@ -90,6 +90,7 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress
#define ZgatewayRF2
#define ZgatewayIR
#define ZgatewayBT
#define Zgateway2G
#define ZactuatorONOFF
#define ZsensorINA226
#define ZsensorHCSR501
@@ -102,6 +103,7 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress
#elif ESP32
#define ZgatewayRF
#define ZgatewayRF2
//#define Zgateway2G (not tested yet)
//#define ZgatewayIR
#define ZgatewayBT
#define ZactuatorONOFF
@@ -114,6 +116,7 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress
//#define ZgatewayRFM69 // If you uncomment this you can't use RF and BT due to the fact that RF use also D8 and BT use also D6/D7
#else // for arduino mega + W5100
#define ZgatewayRF
//#define Zgateway2G (not tested yet)
//#define ZgatewayRF2 // too big for UNO
//#define ZgatewayRFM69 not tested
//#define ZgatewayIR