Merge pull request #354 from GertSanders/development

Adding SMS Gateway node example and supporting library.
This commit is contained in:
Henrik Ekblad
2016-01-17 16:33:42 +01:00
16 changed files with 4150 additions and 0 deletions
@@ -0,0 +1,10 @@
language: c
sudo: false
before_install:
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh)
script:
- build_main_platforms
notifications:
email:
on_success: change
on_failure: change
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,257 @@
/***************************************************
This is a library for our Adafruit FONA Cellular Module
Designed specifically to work with the Adafruit FONA
----> http://www.adafruit.com/products/1946
----> http://www.adafruit.com/products/1963
These displays use TTL Serial to communicate, 2 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#ifndef ADAFRUIT_FONA_H
#define ADAFRUIT_FONA_H
#if (ARDUINO >= 100)
#include "Arduino.h"
#ifndef __SAM3X8E__ // Arduino Due doesn't support SoftwareSerial
#include <SoftwareSerial.h>
#endif
#else
#include "WProgram.h"
#include <NewSoftSerial.h>
#endif
#define ADAFRUIT_FONA_DEBUG
#define FONA800L 1
#define FONA800H 6
#define FONA808_V1 2
#define FONA808_V2 3
#define FONA3G_A 4
#define FONA3G_E 5
#define FONA_HEADSETAUDIO 0
#define FONA_EXTAUDIO 1
#define FONA_STTONE_DIALTONE 1
#define FONA_STTONE_BUSY 2
#define FONA_STTONE_CONGESTION 3
#define FONA_STTONE_PATHACK 4
#define FONA_STTONE_DROPPED 5
#define FONA_STTONE_ERROR 6
#define FONA_STTONE_CALLWAIT 7
#define FONA_STTONE_RINGING 8
#define FONA_STTONE_BEEP 16
#define FONA_STTONE_POSTONE 17
#define FONA_STTONE_ERRTONE 18
#define FONA_STTONE_INDIANDIALTONE 19
#define FONA_STTONE_USADIALTONE 20
#define FONA_DEFAULT_TIMEOUT_MS 500
#define FONA_HTTP_GET 0
#define FONA_HTTP_POST 1
#define FONA_HTTP_HEAD 2
class Adafruit_FONA : public Stream {
public:
Adafruit_FONA(int8_t r);
boolean begin(Stream &port);
uint8_t type();
// Stream
int available(void);
size_t write(uint8_t x);
int read(void);
int peek(void);
void flush();
// FONA 3G requirements
boolean setBaudrate(uint16_t baud);
// RTC
boolean enableRTC(uint8_t i);
boolean readRTC(uint8_t *year, uint8_t *month, uint8_t *date, uint8_t *hr, uint8_t *min, uint8_t *sec);
// Battery and ADC
boolean getADCVoltage(uint16_t *v);
boolean getBattPercent(uint16_t *p);
boolean getBattVoltage(uint16_t *v);
// SIM query
uint8_t unlockSIM(char *pin);
uint8_t getSIMCCID(char *ccid);
uint8_t getNetworkStatus(void);
uint8_t getRSSI(void);
// IMEI
uint8_t getIMEI(char *imei);
// set Audio output
boolean setAudio(uint8_t a);
boolean setVolume(uint8_t i);
uint8_t getVolume(void);
boolean playToolkitTone(uint8_t t, uint16_t len);
boolean setMicVolume(uint8_t a, uint8_t level);
boolean playDTMF(char tone);
// FM radio functions.
boolean tuneFMradio(uint16_t station);
boolean FMradio(boolean onoff, uint8_t a = FONA_HEADSETAUDIO);
boolean setFMVolume(uint8_t i);
int8_t getFMVolume();
int8_t getFMSignalLevel(uint16_t station);
// SMS handling
boolean setSMSInterrupt(uint8_t i);
uint8_t getSMSInterrupt(void);
int8_t getNumSMS(void);
boolean readSMS(uint8_t i, char *smsbuff, uint16_t max, uint16_t *readsize);
boolean sendSMS(char *smsaddr, char *smsmsg);
boolean deleteSMS(uint8_t i);
boolean getSMSSender(uint8_t i, char *sender, int senderlen);
// Time
boolean enableNetworkTimeSync(boolean onoff);
boolean enableNTPTimeSync(boolean onoff, const __FlashStringHelper *ntpserver=0);
boolean getTime(char *buff, uint16_t maxlen);
// GPRS handling
boolean enableGPRS(boolean onoff);
uint8_t GPRSstate(void);
boolean getGSMLoc(uint16_t *replycode, char *buff, uint16_t maxlen);
boolean getGSMLoc(float *lat, float *lon);
void setGPRSNetworkSettings(const __FlashStringHelper *apn, const __FlashStringHelper *username=0, const __FlashStringHelper *password=0);
// GPS handling
boolean enableGPS(boolean onoff);
int8_t GPSstatus(void);
uint8_t getGPS(uint8_t arg, char *buffer, uint8_t maxbuff);
boolean getGPS(float *lat, float *lon, float *speed_kph=0, float *heading=0, float *altitude=0);
boolean enableGPSNMEA(uint8_t nmea);
// TCP raw connections
boolean TCPconnect(char *server, uint16_t port);
boolean TCPclose(void);
boolean TCPconnected(void);
boolean TCPsend(char *packet, uint8_t len);
uint16_t TCPavailable(void);
uint16_t TCPread(uint8_t *buff, uint8_t len);
// HTTP low level interface (maps directly to SIM800 commands).
boolean HTTP_init();
boolean HTTP_term();
void HTTP_para_start(const __FlashStringHelper *parameter, boolean quoted = true);
boolean HTTP_para_end(boolean quoted = true);
boolean HTTP_para(const __FlashStringHelper *parameter, const char *value);
boolean HTTP_para(const __FlashStringHelper *parameter, const __FlashStringHelper *value);
boolean HTTP_para(const __FlashStringHelper *parameter, int32_t value);
boolean HTTP_data(uint32_t size, uint32_t maxTime=10000);
boolean HTTP_action(uint8_t method, uint16_t *status, uint16_t *datalen, int32_t timeout = 10000);
boolean HTTP_readall(uint16_t *datalen);
boolean HTTP_ssl(boolean onoff);
// HTTP high level interface (easier to use, less flexible).
boolean HTTP_GET_start(char *url, uint16_t *status, uint16_t *datalen);
void HTTP_GET_end(void);
boolean HTTP_POST_start(char *url, const __FlashStringHelper *contenttype, const uint8_t *postdata, uint16_t postdatalen, uint16_t *status, uint16_t *datalen);
void HTTP_POST_end(void);
void setUserAgent(const __FlashStringHelper *useragent);
// HTTPS
void setHTTPSRedirect(boolean onoff);
// PWM (buzzer)
boolean setPWM(uint16_t period, uint8_t duty = 50);
// Phone calls
boolean callPhone(char *phonenum);
boolean hangUp(void);
boolean pickUp(void);
boolean callerIdNotification(boolean enable, uint8_t interrupt = 0);
boolean incomingCallNumber(char* phonenum);
// Helper functions to verify responses.
boolean expectReply(const __FlashStringHelper *reply, uint16_t timeout = 10000);
boolean sendCheckReply(char *send, char *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
boolean sendCheckReply(const __FlashStringHelper *send, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
protected:
int8_t _rstpin;
uint8_t _type;
char replybuffer[255];
const __FlashStringHelper *apn;
const __FlashStringHelper *apnusername;
const __FlashStringHelper *apnpassword;
boolean httpsredirect;
const __FlashStringHelper *useragent;
// HTTP helpers
boolean HTTP_setup(char *url);
void flushInput();
uint16_t readRaw(uint16_t b);
uint8_t readline(uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS, boolean multiline = false);
uint8_t getReply(char *send, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
uint8_t getReply(const __FlashStringHelper *send, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
uint8_t getReply(const __FlashStringHelper *prefix, char *suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
uint8_t getReply(const __FlashStringHelper *prefix, int32_t suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
uint8_t getReply(const __FlashStringHelper *prefix, int32_t suffix1, int32_t suffix2, uint16_t timeout); // Don't set default value or else function call is ambiguous.
uint8_t getReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
boolean sendCheckReply(const __FlashStringHelper *prefix, char *suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
boolean sendCheckReply(const __FlashStringHelper *prefix, int32_t suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
boolean sendCheckReply(const __FlashStringHelper *prefix, int32_t suffix, int32_t suffix2, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
boolean sendCheckReplyQuoted(const __FlashStringHelper *prefix, const __FlashStringHelper *suffix, const __FlashStringHelper *reply, uint16_t timeout = FONA_DEFAULT_TIMEOUT_MS);
boolean parseReply(const __FlashStringHelper *toreply,
uint16_t *v, char divider = ',', uint8_t index=0);
boolean parseReply(const __FlashStringHelper *toreply,
char *v, char divider = ',', uint8_t index=0);
boolean parseReplyQuoted(const __FlashStringHelper *toreply,
char *v, int maxlen, char divider, uint8_t index);
boolean sendParseReply(const __FlashStringHelper *tosend,
const __FlashStringHelper *toreply,
uint16_t *v, char divider = ',', uint8_t index=0);
static boolean _incomingCall;
static void onIncomingCall();
Stream *mySerial;
};
class Adafruit_FONA_3G : public Adafruit_FONA {
public:
Adafruit_FONA_3G (int8_t r) : Adafruit_FONA(r) { _type = FONA3G_A; }
boolean getBattVoltage(uint16_t *v);
boolean playToolkitTone(uint8_t t, uint16_t len);
boolean hangUp(void);
boolean pickUp(void);
boolean enableGPRS(boolean onoff);
boolean enableGPS(boolean onoff);
protected:
boolean parseReply(const __FlashStringHelper *toreply,
float *f, char divider, uint8_t index);
boolean sendParseReply(const __FlashStringHelper *tosend,
const __FlashStringHelper *toreply,
float *f, char divider = ',', uint8_t index=0);
};
#endif
+29
View File
@@ -0,0 +1,29 @@
# Adafruit FONA Library [![Build Status](https://secure.travis-ci.org/adafruit/Adafruit_FONA_Library.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_FONA_Library)
**This library requires Arduino v1.0.6 or higher**
This is a library for the Adafruit FONA Cellular GSM Breakouts etc
Designed specifically to work with the Adafruit FONA Breakout
* https://www.adafruit.com/products/1946
* https://www.adafruit.com/products/1963
* http://www.adafruit.com/products/2468
* http://www.adafruit.com/products/2542
These modules use TTL Serial to communicate, 2 pins are required to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Check out the links above for our tutorials and wiring diagrams
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
With updates from Samy Kamkar
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_FONA
Check that the Adafruit_FONA folder contains Adafruit_FONA.cpp and Adafruit_FONA.h
Place the Adafruit_FONA library folder your *arduinosketchfolder*/libraries/ folder.
You may need to create the libraries subfolder if its your first library. Restart the IDE.
@@ -0,0 +1,77 @@
/***************************************************
This is an example for our Adafruit FONA Cellular Module
since the FONA 3G does not do auto-baud very well, this demo
fixes the baud rate to 4800 from the default 115200
Designed specifically to work with the Adafruit FONA 3G
----> http://www.adafruit.com/products/2691
----> http://www.adafruit.com/products/2687
These cellular modules use TTL Serial to communicate, 2 pins are
required to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_FONA.h"
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
// this is a large buffer for replies
char replybuffer[255];
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
// HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);
void setup() {
while (!Serial);
Serial.begin(115200);
Serial.println(F("FONA set baudrate"));
Serial.println(F("First trying 115200 baud"));
// start at 115200 baud
fonaSerial->begin(115200);
fona.begin(*fonaSerial);
// send the command to reset the baud rate to 4800
fona.setBaudrate(4800);
// restart with 4800 baud
fonaSerial->begin(4800);
Serial.println(F("Initializing @ 4800 baud..."));
if (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
while(1);
}
Serial.println(F("FONA is OK"));
// Print module IMEI number.
char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!
uint8_t imeiLen = fona.getIMEI(imei);
if (imeiLen > 0) {
Serial.print("Module IMEI: "); Serial.println(imei);
}
}
void loop() {
}
@@ -0,0 +1,122 @@
/***************************************************
This is an example for our Adafruit FONA Cellular Module
Designed specifically to work with the Adafruit FONA
----> http://www.adafruit.com/products/1946
----> http://www.adafruit.com/products/1963
----> http://www.adafruit.com/products/2468
----> http://www.adafruit.com/products/2542
These cellular modules use TTL Serial to communicate, 2 pins are
required to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
/*
THIS CODE IS STILL IN PROGRESS!
Open up the serial console on the Arduino at 115200 baud to interact with FONA
This code will receive an SMS, identify the sender's phone number, and automatically send a response
*/
#include "Adafruit_FONA.h"
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
// this is a large buffer for replies
char replybuffer[255];
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
// HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);
void setup() {
while (!Serial);
Serial.begin(115200);
Serial.println(F("FONA SMS caller ID test"));
Serial.println(F("Initializing....(May take 3 seconds)"));
// make it slow so its easy to read!
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
while(1);
}
Serial.println(F("FONA is OK"));
// Print SIM card IMEI number.
char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!
uint8_t imeiLen = fona.getIMEI(imei);
if (imeiLen > 0) {
Serial.print("SIM card IMEI: "); Serial.println(imei);
}
Serial.println("FONA Ready");
}
char fonaInBuffer[64]; //for notifications from the FONA
void loop() {
char* bufPtr = fonaInBuffer; //handy buffer pointer
if (fona.available()) //any data available from the FONA?
{
int slot = 0; //this will be the slot number of the SMS
int charCount = 0;
//Read the notification into fonaInBuffer
do {
*bufPtr = fona.read();
Serial.write(*bufPtr);
delay(1);
} while ((*bufPtr++ != '\n') && (fona.available()) && (++charCount < (sizeof(fonaInBuffer)-1)));
//Add a terminal NULL to the notification string
*bufPtr = 0;
//Scan the notification string for an SMS received notification.
// If it's an SMS message, we'll get the slot number in 'slot'
if (1 == sscanf(fonaInBuffer, "+CMTI: \"SM\",%d", &slot)) {
Serial.print("slot: "); Serial.println(slot);
char callerIDbuffer[32]; //we'll store the SMS sender number in here
// Retrieve SMS sender address/phone number.
if (! fona.getSMSSender(slot, callerIDbuffer, 31)) {
Serial.println("Didn't find SMS message in slot!");
}
Serial.print(F("FROM: ")); Serial.println(callerIDbuffer);
//Send back an automatic response
Serial.println("Sending reponse...");
if (!fona.sendSMS(callerIDbuffer, "Hey, I got your text!")) {
Serial.println(F("Failed"));
} else {
Serial.println(F("Sent!"));
}
}
}
}
@@ -0,0 +1,851 @@
/***************************************************
This is an example for our Adafruit FONA Cellular Module
Designed specifically to work with the Adafruit FONA
----> http://www.adafruit.com/products/1946
----> http://www.adafruit.com/products/1963
----> http://www.adafruit.com/products/2468
----> http://www.adafruit.com/products/2542
These cellular modules use TTL Serial to communicate, 2 pins are
required to interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
/*
THIS CODE IS STILL IN PROGRESS!
Open up the serial console on the Arduino at 115200 baud to interact with FONA
Note that if you need to set a GPRS APN, username, and password scroll down to
the commented section below at the end of the setup() function.
*/
#include "Adafruit_FONA.h"
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
// this is a large buffer for replies
char replybuffer[255];
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
// HardwareSerial *fonaSerial = &Serial1;
// Use this for FONA 800 and 808s
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Use this one for FONA 3G
//Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);
uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0);
uint8_t type;
void setup() {
while (!Serial);
Serial.begin(115200);
Serial.println(F("FONA basic test"));
Serial.println(F("Initializing....(May take 3 seconds)"));
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
while (1);
}
type = fona.type();
Serial.println(F("FONA is OK"));
Serial.print(F("Found "));
switch (type) {
case FONA800L:
Serial.println(F("FONA 800L")); break;
case FONA800H:
Serial.println(F("FONA 800H")); break;
case FONA808_V1:
Serial.println(F("FONA 808 (v1)")); break;
case FONA808_V2:
Serial.println(F("FONA 808 (v2)")); break;
case FONA3G_A:
Serial.println(F("FONA 3G (American)")); break;
case FONA3G_E:
Serial.println(F("FONA 3G (European)")); break;
default:
Serial.println(F("???")); break;
}
// Print module IMEI number.
char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!
uint8_t imeiLen = fona.getIMEI(imei);
if (imeiLen > 0) {
Serial.print("Module IMEI: "); Serial.println(imei);
}
// Optionally configure a GPRS APN, username, and password.
// You might need to do this to access your network's GPRS/data
// network. Contact your provider for the exact APN, username,
// and password values. Username and password are optional and
// can be removed, but APN is required.
//fona.setGPRSNetworkSettings(F("your APN"), F("your username"), F("your password"));
// Optionally configure HTTP gets to follow redirects over SSL.
// Default is not to follow SSL redirects, however if you uncomment
// the following line then redirects over SSL will be followed.
//fona.setHTTPSRedirect(true);
printMenu();
}
void printMenu(void) {
Serial.println(F("-------------------------------------"));
Serial.println(F("[?] Print this menu"));
Serial.println(F("[a] read the ADC 2.8V max (FONA800 & 808)"));
Serial.println(F("[b] read the Battery V and % charged"));
Serial.println(F("[C] read the SIM CCID"));
Serial.println(F("[U] Unlock SIM with PIN code"));
Serial.println(F("[i] read RSSI"));
Serial.println(F("[n] get Network status"));
Serial.println(F("[v] set audio Volume"));
Serial.println(F("[V] get Volume"));
Serial.println(F("[H] set Headphone audio (FONA800 & 808)"));
Serial.println(F("[e] set External audio (FONA800 & 808)"));
Serial.println(F("[T] play audio Tone"));
Serial.println(F("[P] PWM/Buzzer out (FONA800 & 808)"));
// FM (SIM800 only!)
Serial.println(F("[f] tune FM radio (FONA800)"));
Serial.println(F("[F] turn off FM (FONA800)"));
Serial.println(F("[m] set FM volume (FONA800)"));
Serial.println(F("[M] get FM volume (FONA800)"));
Serial.println(F("[q] get FM station signal level (FONA800)"));
// Phone
Serial.println(F("[c] make phone Call"));
Serial.println(F("[h] Hang up phone"));
Serial.println(F("[p] Pick up phone"));
// SMS
Serial.println(F("[N] Number of SMSs"));
Serial.println(F("[r] Read SMS #"));
Serial.println(F("[R] Read All SMS"));
Serial.println(F("[d] Delete SMS #"));
Serial.println(F("[s] Send SMS"));
// Time
Serial.println(F("[y] Enable network time sync (FONA 800 & 808)"));
Serial.println(F("[Y] Enable NTP time sync (GPRS FONA 800 & 808)"));
Serial.println(F("[t] Get network time"));
// GPRS
Serial.println(F("[G] Enable GPRS"));
Serial.println(F("[g] Disable GPRS"));
Serial.println(F("[l] Query GSMLOC (GPRS)"));
Serial.println(F("[w] Read webpage (GPRS)"));
Serial.println(F("[W] Post to website (GPRS)"));
// GPS
if ((type == FONA3G_A) || (type == FONA3G_E) || (type == FONA808_V1) || (type == FONA808_V2)) {
Serial.println(F("[O] Turn GPS on (FONA 808 & 3G)"));
Serial.println(F("[o] Turn GPS off (FONA 808 & 3G)"));
Serial.println(F("[L] Query GPS location (FONA 808 & 3G)"));
if (type == FONA808_V1) {
Serial.println(F("[x] GPS fix status (FONA808 v1 only)"));
}
Serial.println(F("[E] Raw NMEA out (FONA808)"));
}
Serial.println(F("[S] create Serial passthru tunnel"));
Serial.println(F("-------------------------------------"));
Serial.println(F(""));
}
void loop() {
Serial.print(F("FONA> "));
while (! Serial.available() ) {
if (fona.available()) {
Serial.write(fona.read());
}
}
char command = Serial.read();
Serial.println(command);
switch (command) {
case '?': {
printMenu();
break;
}
case 'a': {
// read the ADC
uint16_t adc;
if (! fona.getADCVoltage(&adc)) {
Serial.println(F("Failed to read ADC"));
} else {
Serial.print(F("ADC = ")); Serial.print(adc); Serial.println(F(" mV"));
}
break;
}
case 'b': {
// read the battery voltage and percentage
uint16_t vbat;
if (! fona.getBattVoltage(&vbat)) {
Serial.println(F("Failed to read Batt"));
} else {
Serial.print(F("VBat = ")); Serial.print(vbat); Serial.println(F(" mV"));
}
if (! fona.getBattPercent(&vbat)) {
Serial.println(F("Failed to read Batt"));
} else {
Serial.print(F("VPct = ")); Serial.print(vbat); Serial.println(F("%"));
}
break;
}
case 'U': {
// Unlock the SIM with a PIN code
char PIN[5];
flushSerial();
Serial.println(F("Enter 4-digit PIN"));
readline(PIN, 3);
Serial.println(PIN);
Serial.print(F("Unlocking SIM card: "));
if (! fona.unlockSIM(PIN)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
case 'C': {
// read the CCID
fona.getSIMCCID(replybuffer); // make sure replybuffer is at least 21 bytes!
Serial.print(F("SIM CCID = ")); Serial.println(replybuffer);
break;
}
case 'i': {
// read the RSSI
uint8_t n = fona.getRSSI();
int8_t r;
Serial.print(F("RSSI = ")); Serial.print(n); Serial.print(": ");
if (n == 0) r = -115;
if (n == 1) r = -111;
if (n == 31) r = -52;
if ((n >= 2) && (n <= 30)) {
r = map(n, 2, 30, -110, -54);
}
Serial.print(r); Serial.println(F(" dBm"));
break;
}
case 'n': {
// read the network/cellular status
uint8_t n = fona.getNetworkStatus();
Serial.print(F("Network status "));
Serial.print(n);
Serial.print(F(": "));
if (n == 0) Serial.println(F("Not registered"));
if (n == 1) Serial.println(F("Registered (home)"));
if (n == 2) Serial.println(F("Not registered (searching)"));
if (n == 3) Serial.println(F("Denied"));
if (n == 4) Serial.println(F("Unknown"));
if (n == 5) Serial.println(F("Registered roaming"));
break;
}
/*** Audio ***/
case 'v': {
// set volume
flushSerial();
if ( (type == FONA3G_A) || (type == FONA3G_E) ) {
Serial.print(F("Set Vol [0-8] "));
} else {
Serial.print(F("Set Vol % [0-100] "));
}
uint8_t vol = readnumber();
Serial.println();
if (! fona.setVolume(vol)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
case 'V': {
uint8_t v = fona.getVolume();
Serial.print(v);
if ( (type == FONA3G_A) || (type == FONA3G_E) ) {
Serial.println(" / 8");
} else {
Serial.println("%");
}
break;
}
case 'H': {
// Set Headphone output
if (! fona.setAudio(FONA_HEADSETAUDIO)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
fona.setMicVolume(FONA_HEADSETAUDIO, 15);
break;
}
case 'e': {
// Set External output
if (! fona.setAudio(FONA_EXTAUDIO)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
fona.setMicVolume(FONA_EXTAUDIO, 10);
break;
}
case 'T': {
// play tone
flushSerial();
Serial.print(F("Play tone #"));
uint8_t kittone = readnumber();
Serial.println();
// play for 1 second (1000 ms)
if (! fona.playToolkitTone(kittone, 1000)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
/*** FM Radio ***/
case 'f': {
// get freq
flushSerial();
Serial.print(F("FM Freq (eg 1011 == 101.1 MHz): "));
uint16_t station = readnumber();
Serial.println();
// FM radio ON using headset
if (fona.FMradio(true, FONA_HEADSETAUDIO)) {
Serial.println(F("Opened"));
}
if (! fona.tuneFMradio(station)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("Tuned"));
}
break;
}
case 'F': {
// FM radio off
if (! fona.FMradio(false)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
case 'm': {
// Set FM volume.
flushSerial();
Serial.print(F("Set FM Vol [0-6]:"));
uint8_t vol = readnumber();
Serial.println();
if (!fona.setFMVolume(vol)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
case 'M': {
// Get FM volume.
uint8_t fmvol = fona.getFMVolume();
if (fmvol < 0) {
Serial.println(F("Failed"));
} else {
Serial.print(F("FM volume: "));
Serial.println(fmvol, DEC);
}
break;
}
case 'q': {
// Get FM station signal level (in decibels).
flushSerial();
Serial.print(F("FM Freq (eg 1011 == 101.1 MHz): "));
uint16_t station = readnumber();
Serial.println();
int8_t level = fona.getFMSignalLevel(station);
if (level < 0) {
Serial.println(F("Failed! Make sure FM radio is on (tuned to station)."));
} else {
Serial.print(F("Signal level (dB): "));
Serial.println(level, DEC);
}
break;
}
/*** PWM ***/
case 'P': {
// PWM Buzzer output @ 2KHz max
flushSerial();
Serial.print(F("PWM Freq, 0 = Off, (1-2000): "));
uint16_t freq = readnumber();
Serial.println();
if (! fona.setPWM(freq)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
/*** Call ***/
case 'c': {
// call a phone!
char number[30];
flushSerial();
Serial.print(F("Call #"));
readline(number, 30);
Serial.println();
Serial.print(F("Calling ")); Serial.println(number);
if (!fona.callPhone(number)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("Sent!"));
}
break;
}
case 'h': {
// hang up!
if (! fona.hangUp()) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
case 'p': {
// pick up!
if (! fona.pickUp()) {
Serial.println(F("Failed"));
} else {
Serial.println(F("OK!"));
}
break;
}
/*** SMS ***/
case 'N': {
// read the number of SMS's!
int8_t smsnum = fona.getNumSMS();
if (smsnum < 0) {
Serial.println(F("Could not read # SMS"));
} else {
Serial.print(smsnum);
Serial.println(F(" SMS's on SIM card!"));
}
break;
}
case 'r': {
// read an SMS
flushSerial();
Serial.print(F("Read #"));
uint8_t smsn = readnumber();
Serial.print(F("\n\rReading SMS #")); Serial.println(smsn);
// Retrieve SMS sender address/phone number.
if (! fona.getSMSSender(smsn, replybuffer, 250)) {
Serial.println("Failed!");
break;
}
Serial.print(F("FROM: ")); Serial.println(replybuffer);
// Retrieve SMS value.
uint16_t smslen;
if (! fona.readSMS(smsn, replybuffer, 250, &smslen)) { // pass in buffer and max len!
Serial.println("Failed!");
break;
}
Serial.print(F("***** SMS #")); Serial.print(smsn);
Serial.print(" ("); Serial.print(smslen); Serial.println(F(") bytes *****"));
Serial.println(replybuffer);
Serial.println(F("*****"));
break;
}
case 'R': {
// read all SMS
int8_t smsnum = fona.getNumSMS();
uint16_t smslen;
int8_t smsn;
if ( (type == FONA3G_A) || (type == FONA3G_E) ) {
smsn = 0; // zero indexed
smsnum--;
} else {
smsn = 1; // 1 indexed
}
for ( ; smsn <= smsnum; smsn++) {
Serial.print(F("\n\rReading SMS #")); Serial.println(smsn);
if (!fona.readSMS(smsn, replybuffer, 250, &smslen)) { // pass in buffer and max len!
Serial.println(F("Failed!"));
break;
}
// if the length is zero, its a special case where the index number is higher
// so increase the max we'll look at!
if (smslen == 0) {
Serial.println(F("[empty slot]"));
smsnum++;
continue;
}
Serial.print(F("***** SMS #")); Serial.print(smsn);
Serial.print(" ("); Serial.print(smslen); Serial.println(F(") bytes *****"));
Serial.println(replybuffer);
Serial.println(F("*****"));
}
break;
}
case 'd': {
// delete an SMS
flushSerial();
Serial.print(F("Delete #"));
uint8_t smsn = readnumber();
Serial.print(F("\n\rDeleting SMS #")); Serial.println(smsn);
if (fona.deleteSMS(smsn)) {
Serial.println(F("OK!"));
} else {
Serial.println(F("Couldn't delete"));
}
break;
}
case 's': {
// send an SMS!
char sendto[21], message[141];
flushSerial();
Serial.print(F("Send to #"));
readline(sendto, 20);
Serial.println(sendto);
Serial.print(F("Type out one-line message (140 char): "));
readline(message, 140);
Serial.println(message);
if (!fona.sendSMS(sendto, message)) {
Serial.println(F("Failed"));
} else {
Serial.println(F("Sent!"));
}
break;
}
/*** Time ***/
case 'y': {
// enable network time sync
if (!fona.enableNetworkTimeSync(true))
Serial.println(F("Failed to enable"));
break;
}
case 'Y': {
// enable NTP time sync
if (!fona.enableNTPTimeSync(true, F("pool.ntp.org")))
Serial.println(F("Failed to enable"));
break;
}
case 't': {
// read the time
char buffer[23];
fona.getTime(buffer, 23); // make sure replybuffer is at least 23 bytes!
Serial.print(F("Time = ")); Serial.println(buffer);
break;
}
/*********************************** GPS (SIM808 only) */
case 'o': {
// turn GPS off
if (!fona.enableGPS(false))
Serial.println(F("Failed to turn off"));
break;
}
case 'O': {
// turn GPS on
if (!fona.enableGPS(true))
Serial.println(F("Failed to turn on"));
break;
}
case 'x': {
int8_t stat;
// check GPS fix
stat = fona.GPSstatus();
if (stat < 0)
Serial.println(F("Failed to query"));
if (stat == 0) Serial.println(F("GPS off"));
if (stat == 1) Serial.println(F("No fix"));
if (stat == 2) Serial.println(F("2D fix"));
if (stat == 3) Serial.println(F("3D fix"));
break;
}
case 'L': {
// check for GPS location
char gpsdata[120];
fona.getGPS(0, gpsdata, 120);
if (type == FONA808_V1)
Serial.println(F("Reply in format: mode,longitude,latitude,altitude,utctime(yyyymmddHHMMSS),ttff,satellites,speed,course"));
else
Serial.println(F("Reply in format: mode,fixstatus,utctime(yyyymmddHHMMSS),latitude,longitude,altitude,speed,course,fixmode,reserved1,HDOP,PDOP,VDOP,reserved2,view_satellites,used_satellites,reserved3,C/N0max,HPA,VPA"));
Serial.println(gpsdata);
break;
}
case 'E': {
flushSerial();
if (type == FONA808_V1) {
Serial.print(F("GPS NMEA output sentences (0 = off, 34 = RMC+GGA, 255 = all)"));
} else {
Serial.print(F("On (1) or Off (0)? "));
}
uint8_t nmeaout = readnumber();
// turn on NMEA output
fona.enableGPSNMEA(nmeaout);
break;
}
/*********************************** GPRS */
case 'g': {
// turn GPRS off
if (!fona.enableGPRS(false))
Serial.println(F("Failed to turn off"));
break;
}
case 'G': {
// turn GPRS on
if (!fona.enableGPRS(true))
Serial.println(F("Failed to turn on"));
break;
}
case 'l': {
// check for GSMLOC (requires GPRS)
uint16_t returncode;
if (!fona.getGSMLoc(&returncode, replybuffer, 250))
Serial.println(F("Failed!"));
if (returncode == 0) {
Serial.println(replybuffer);
} else {
Serial.print(F("Fail code #")); Serial.println(returncode);
}
break;
}
case 'w': {
// read website URL
uint16_t statuscode;
int16_t length;
char url[80];
flushSerial();
Serial.println(F("NOTE: in beta! Use small webpages to read!"));
Serial.println(F("URL to read (e.g. www.adafruit.com/testwifi/index.html):"));
Serial.print(F("http://")); readline(url, 79);
Serial.println(url);
Serial.println(F("****"));
if (!fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length)) {
Serial.println("Failed!");
break;
}
while (length > 0) {
while (fona.available()) {
char c = fona.read();
// Serial.write is too slow, we'll write directly to Serial register!
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
#else
Serial.write(c);
#endif
length--;
if (! length) break;
}
}
Serial.println(F("\n****"));
fona.HTTP_GET_end();
break;
}
case 'W': {
// Post data to website
uint16_t statuscode;
int16_t length;
char url[80];
char data[80];
flushSerial();
Serial.println(F("NOTE: in beta! Use simple websites to post!"));
Serial.println(F("URL to post (e.g. httpbin.org/post):"));
Serial.print(F("http://")); readline(url, 79);
Serial.println(url);
Serial.println(F("Data to post (e.g. \"foo\" or \"{\"simple\":\"json\"}\"):"));
readline(data, 79);
Serial.println(data);
Serial.println(F("****"));
if (!fona.HTTP_POST_start(url, F("text/plain"), (uint8_t *) data, strlen(data), &statuscode, (uint16_t *)&length)) {
Serial.println("Failed!");
break;
}
while (length > 0) {
while (fona.available()) {
char c = fona.read();
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
#else
Serial.write(c);
#endif
length--;
if (! length) break;
}
}
Serial.println(F("\n****"));
fona.HTTP_POST_end();
break;
}
/*****************************************/
case 'S': {
Serial.println(F("Creating SERIAL TUBE"));
while (1) {
while (Serial.available()) {
delay(1);
fona.write(Serial.read());
}
if (fona.available()) {
Serial.write(fona.read());
}
}
break;
}
default: {
Serial.println(F("Unknown command"));
printMenu();
break;
}
}
// flush input
flushSerial();
while (fona.available()) {
Serial.write(fona.read());
}
}
void flushSerial() {
while (Serial.available())
Serial.read();
}
char readBlocking() {
while (!Serial.available());
return Serial.read();
}
uint16_t readnumber() {
uint16_t x = 0;
char c;
while (! isdigit(c = readBlocking())) {
//Serial.print(c);
}
Serial.print(c);
x = c - '0';
while (isdigit(c = readBlocking())) {
Serial.print(c);
x *= 10;
x += c - '0';
}
return x;
}
uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout) {
uint16_t buffidx = 0;
boolean timeoutvalid = true;
if (timeout == 0) timeoutvalid = false;
while (true) {
if (buffidx > maxbuff) {
//Serial.println(F("SPACE"));
break;
}
while (Serial.available()) {
char c = Serial.read();
//Serial.print(c, HEX); Serial.print("#"); Serial.println(c);
if (c == '\r') continue;
if (c == 0xA) {
if (buffidx == 0) // the first 0x0A is ignored
continue;
timeout = 0; // the second 0x0A is the end of the line
timeoutvalid = true;
break;
}
buff[buffidx] = c;
buffidx++;
}
if (timeoutvalid && timeout == 0) {
//Serial.println(F("TIMEOUT"));
break;
}
delay(1);
}
buff[buffidx] = 0; // null term
return buffidx;
}
@@ -0,0 +1,112 @@
/**
* ___ ___ _ _ _ ___ __ ___ ___ ___ ___
* | __/ _ \| \| | /_\ ( _ )/ \( _ ) / __| _ \/ __|
* | _| (_) | .` |/ _ \ / _ \ () / _ \ | (_ | _/\__ \
* |_| \___/|_|\_/_/ \_\ \___/\__/\___/ \___|_| |___/
*
* This example is meant to work with the Adafruit
* FONA 808 or 3G Shield or Breakout
*
* Copyright: 2015 Adafruit
* Author: Todd Treece
* Licence: MIT
*
*/
#include "Adafruit_FONA.h"
// standard pins for the shield, adjust as necessary
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
// HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Have a FONA 3G? use this object type instead
//Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);
void setup() {
while (! Serial);
Serial.begin(115200);
Serial.println(F("Adafruit FONA 808 & 3G GPS demo"));
Serial.println(F("Initializing FONA... (May take a few seconds)"));
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
while(1);
}
Serial.println(F("FONA is OK"));
// Try to enable GPRS
Serial.println(F("Enabling GPS..."));
fona.enableGPS(true);
}
void loop() {
delay(2000);
float latitude, longitude, speed_kph, heading, speed_mph, altitude;
// if you ask for an altitude reading, getGPS will return false if there isn't a 3D fix
boolean gps_success = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude);
if (gps_success) {
Serial.print("GPS lat:");
Serial.println(latitude, 6);
Serial.print("GPS long:");
Serial.println(longitude, 6);
Serial.print("GPS speed KPH:");
Serial.println(speed_kph);
Serial.print("GPS speed MPH:");
speed_mph = speed_kph * 0.621371192;
Serial.println(speed_mph);
Serial.print("GPS heading:");
Serial.println(heading);
Serial.print("GPS altitude:");
Serial.println(altitude);
} else {
Serial.println("Waiting for FONA GPS 3D fix...");
}
// Fona 3G doesnt have GPRSlocation :/
if ((fona.type() == FONA3G_A) || (fona.type() == FONA3G_E))
return;
// Check for network, then GPRS
Serial.println(F("Checking for Cell network..."));
if (fona.getNetworkStatus() == 1) {
// network & GPRS? Great! Print out the GSM location to compare
boolean gsmloc_success = fona.getGSMLoc(&latitude, &longitude);
if (gsmloc_success) {
Serial.print("GSMLoc lat:");
Serial.println(latitude, 6);
Serial.print("GSMLoc long:");
Serial.println(longitude, 6);
} else {
Serial.println("GSM location failed...");
Serial.println(F("Disabling GPRS"));
fona.enableGPRS(false);
Serial.println(F("Enabling GPRS"));
if (!fona.enableGPRS(true)) {
Serial.println(F("Failed to turn GPRS on"));
}
}
}
}
@@ -0,0 +1,62 @@
// FONA Incoming Call Number Example
// Listens for a call and displays the phone number of the caller (if available).
// Use this example to add phone call detection to your own FONA sketch.
#include "Adafruit_FONA.h"
// Pins which are connected to the FONA.
// Note that this is different from FONAtest!
#define FONA_RX 3
#define FONA_TX 4
#define FONA_RST 5
// Note you need to map interrupt number to pin number
// for your board. On an Uno & Mega interrupt 0 is
// digital pin 2, and on a Leonardo interrupt 0 is
// digital pin 3. See this page for a complete table:
// http://arduino.cc/en/Reference/attachInterrupt
// Make sure this interrupt pin is connected to FONA RI!
#define FONA_RI_INTERRUPT 0
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
// HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
void setup() {
Serial.begin(115200);
Serial.println(F("FONA incoming call example"));
Serial.println(F("Initializing....(May take 3 seconds)"));
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
while(1);
}
Serial.println(F("FONA is OK"));
// Enable incoming call notification.
if(fona.callerIdNotification(true, FONA_RI_INTERRUPT)) {
Serial.println(F("Caller id notification enabled."));
}
else {
Serial.println(F("Caller id notification disabled"));
}
}
void loop(){
// Create a small string buffer to hold incoming call number.
char phone[32] = {0};
// Check for an incoming call. Will return true if a call is incoming.
if(fona.incomingCallNumber(phone)){
Serial.println(F("RING!"));
Serial.print(F("Phone Number: "));
Serial.println(phone);
}
}
@@ -0,0 +1,9 @@
name=Adafruit FONA Library
version=1.3.0
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for the Adafruit FONA
paragraph=Arduino library for the Adafruit FONA
category=Communication
url=https://github.com/adafruit/Adafruit_FONA_Library
architectures=*
@@ -0,0 +1,646 @@
/*
SMS Gateway
This node works as a SMS gateway, receiving and sending SMS messages at the request of other nodes
It needs to have a fixed ID to be able to be addessed within a MySensors network.
As it is easy to remember I chose the ID 123.
Once the node is sent an initiating SMS, it will respond to the received calling number as it's "owner". This way you do not
need to hardcode your number in the sketch. But to make it operational, you will need to send at least 1 SMS to it
with the prededfined text MYPASSWORD (see below in the definitions, you set your own string).
The node should respond with CONFIRMOWNER, you can set this string in de definitions below.
The allow another phone to control the node and receive messages, the "owner" needs to release the node by sending a SMS with
the text MYRELEASEWORD. Again you can set this string in the definitions below.
The node will then again become ownerless and ignore all messages and SMS's.
If the node has an owner and another phone sends a message to the node, it will inform the owner of a "take over attempt".
You can sent V_TEXT to other nodes in your network by using the following format:
"N021:xxx.any.25.characters.xxx"
Anything sent after the "N021:" will be sent to the node with address 021. A V_TEXT has a maximum length of 25 charters. Adding the node address make the SMS length 30 charters.
The SMS buffer is 31 characters long.
A node address can have a value 000 (the controller) and any value between 001 and 254. Values higher then 254 are ignored and nothing will be done with the
received SMS, apart from informing the controller that this SMS was received.
Sending a SMS to the SMS Gateway with the address of the SMS Gateway itself will result in the SMS Gateway sending the same SMS back.
So if you send the following SMS to your SMS Gateway:
"N123:Are you there ?"
You will receive a SMS with the content ""N123:Are you there ?"
What is happening ?
The SMS Gateway receives a SMS adressed to the node 123, the SMS Gateway sends a copy of the received SMS to the controller and sends a message with content "Are you there ?"
to the node 123. Since node 123 is the SMS Gateway receiving a message, it will pass on this message as a SMS to the owner in the format specified earlier.
So a text SMS is sent with content "N123:Are you there?"
If a node sends a V_TEXT "Garagedoor is opened" to the SMS Gateway, the SMS gateway will pass this on to the owner's GSM in the format below:
"N011:Garagedoor is opened"
Address from the node sending the text is sent first (in this case "N011:"), and then the contents of the V_TEXT itself is appended ("Garagedoor is opened").
You need a SIM800L module hooked to an atmega328 based MySensor node via softserial port. This sketch was made for my AC capable
board wich allows use of a SIM800L module. More on that board on the forum at this location:
http://forum.mysensors.org/topic/2374/50mm-x-50mm-board-with-different-powering-options/10
or
https://www.openhardware.io/view/11/ACDCBatteries-capable-atmega328p-board
Nodes that want to inform an GSM owner via the SMS Gateway need to have the capacity to send a V_TEXT.
Even nodes that sleep most of the time can send messages to any other node. You just need to define a V_TEXT message type.
Nodes that need to react to SMS messages with instructions, need to be able to receive V_TEXT and need to be reachable (always on).
So battery based nodes will not be the best candidates as actuators based on SMS.
This example code is in the public domain.
modified 10 oktober 2015 version 1.0
modified 6 january 2016 version 1.1
modified 15 january 2016 version 1.2
by GertSanders on the MySensors forum
Uses the Adafruit FONA library to drive the SIM800L, this need to be included in your library to compile this sketch.
To do: create a buffer structure to handle several incoming messages from nodes or phone.
*/
#define SKETCHNAME "SMSGatewayNode"
#define SKETCHVERSION "1.2"
// Enable debug prints to serial monitor
//#define MY_DEBUG
//#define MY_DEBUG_VERBOSE
//#define MY_BAUD_RATE 57600
#define MY_NODE_ID 123
#define GATEWAY_ID 0
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#define MY_RADIO_RFM69
// defines for sensors
//#define BATTERYLEVEL 0
#define SMSTEXT 1
// Enable repeater functionality for this node
//#define MY_REPEATER_FEATURE
// All includes
#include <SPI.h>
#include <SoftwareSerial.h>
#include <Adafruit_FONA.h>
#include <MySensor.h>
// Pin definitions and other defines
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
#define defaultledpin 8 // usually this is pin 13, but better to use another digital pin
// constants
#define MAXSMSLENGTH 30 // No need for longer messages from GSM's as V_TEXT is limiting what can be sent to the other nodes. Node addresses are maximum 000 -> 255
#define MAXMSGLENGTH 25 // limiting factor is the payload of V_TEXT, which is 25 chars. Nodes will never send you more then this in 1 message.
#define MAXNUMBERLENGTH 12 // based on "plus" sign, a country prefix and national number. Example in Belgium: +32 123 45 67
#define MAXNODEID 254 // highest value a node ID can have
// following strings need to be set by you, maximum length is 30 CHARS.
#define MYPASSWORD "Password" // replace this with your preferred passphrase to gain ownership
#define CONFIRMOWNER "I am yours" // replace this string if your partner is of the untrusting type ;-)
#define MYRELEASEWORD "I release you" // replace this with your preferred release confirmation
// variables
boolean KnowMyOwner = false;
boolean MsgReceived = false;
uint16_t smslen = 0;
int8_t smsnum = 0;
int bufferindex = 0;
char smsbuffer[MAXSMSLENGTH + 1] = "";
char msgbuffer[MAXMSGLENGTH + 1] = "";
char nodemsgbuffer[MAXMSGLENGTH + 1] = "";
char nodeaddress[5];
char Numbers[11] = "0123456789";
char myOwnersNumber[MAXNUMBERLENGTH + 1] = "";
char ReceivedNumber[MAXNUMBERLENGTH + 1] = "";
// Instantiate objects
MyMessage SMSMsg(SMSTEXT, V_TEXT);
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
/////////////////////////////////////////////////////////////////////////
// supporting functions.
/////////////////////////////////////////////////////////////////////////
void blipled()
{
digitalWrite(defaultledpin, HIGH); // turn the LED on (HIGH is the voltage level)
wait(3); // wait for a second
digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage HIGH
wait(100); // wait for a second
digitalWrite(defaultledpin, HIGH); // turn the LED on (HIGH is the voltage level)
wait(3); // wait for a second
digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage HIGH
}
/////////////////////////////////////////////////////////////////////////
int GetNodeID()
{
int TheAddress = -1;
TheAddress = ((smsbuffer[1] - 48) * 100) + ((smsbuffer[2] - 48) * 10) + (smsbuffer[3] - 48);
return TheAddress;
}
/////////////////////////////////////////////////////////////////////////
bool IsAddressingNode()
{
if (strlen(smsbuffer) > 5)
{ // at least something to check
if ((smsbuffer[0] == 'N') && (smsbuffer[4] == ':') && (strchr(Numbers, smsbuffer[1]) != NULL) && (strchr(Numbers, smsbuffer[2]) != NULL) && (strchr(Numbers, smsbuffer[3]) != NULL))
{
#ifdef MY_DEBUG
Serial.print("Message addressed to: ");
Serial.println(GetNodeID());
#endif
if (GetNodeID() <= MAXNODEID)
return true;
else
return false;
}
else
{
return false;
}
}
else
{
return false;
}
}
/////////////////////////////////////////////////////////////////////////
char* GetMessageContent(char incomingsmsbuffer[MAXSMSLENGTH])
{
strcpy(nodemsgbuffer, "");
for (int i = 5; i < MAXSMSLENGTH; i++)
{
nodemsgbuffer[i - 5] = incomingsmsbuffer[i];
}
return nodemsgbuffer;
}
/////////////////////////////////////////////////////////////////////////
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo(SKETCHNAME, SKETCHVERSION);
wait(500);
// node ID is 123
present(SMSTEXT, S_INFO);
wait(500);
}
/////////////////////////////////////////////////////////////////////////
void receive(const MyMessage & message)
{
#ifdef MY_DEBUG
Serial.print(F("Incoming from sensor: "));
Serial.print(message.sensor);
#endif
if ((message.type == V_TEXT) and (!MsgReceived))
{
sprintf(smsbuffer, "N%d:", message.sender);
strcat(smsbuffer, message.getString());
strcpy(msgbuffer, message.getString());
MsgReceived = true;
#ifdef MY_DEBUG
Serial.print(F(", New text: "));
Serial.print(message.getString());
#endif
// send a copy of the received message to the controller
}
#ifdef MY_DEBUG
Serial.println();
#endif
} // end: void receive()
/////////////////////////////////////////////////////////////////////////
void clearSMSmemory()
{
int8_t smsnum = fona.getNumSMS();
while (smsnum > 0)
{
fona.deleteSMS(smsnum);
smsnum--;
}
}
/////////////////////////////////////////////////////////////////////////
// the setup function runs once when you press reset or power the board
/////////////////////////////////////////////////////////////////////////
void setup()
{
KnowMyOwner = false;
MsgReceived = false;
SMSMsg.setDestination(GATEWAY_ID);
// initialize digital LEDpin as an output.
pinMode(defaultledpin, OUTPUT);
digitalWrite(defaultledpin, HIGH); // turn the LED on by making the voltage HIGH
#ifdef MY_DEBUG
Serial.println(F("SIM800L basic test"));
Serial.println(F("Initializing....(May take 3 seconds)"));
Serial.println(F("starting SIM800L"));
#endif
fonaSerial->begin(4800);
if (! fona.begin(*fonaSerial))
{
#ifdef MY_DEBUG
Serial.println(F("Couldn't find SIM800L"));
#endif
while (1);
}
#ifdef MY_DEBUG
Serial.println(F("SIM800L is OK"));
#endif
digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage LOW
wait(250); // wait for a bit
digitalWrite(defaultledpin, HIGH); // turn the LED on by making the voltage HIGH
#ifdef MY_DEBUG
// Print SIM card IMEI number.
char imei[15] = {0}; // MUST use a 16 character buffer for IMEI!
uint8_t imeiLen = fona.getIMEI(imei);
if (imeiLen > 0) {
Serial.print(F("SIM card IMEI: ")); Serial.println(imei);
}
#endif
smsnum = fona.getNumSMS();
if (smsnum < 0)
{
#ifdef MY_DEBUG
Serial.println(F("Could not read # SMS"));
#endif
}
else
{
#ifdef MY_DEBUG
Serial.print(smsnum);
Serial.println(F(" SMS's on SIM card!"));
#endif
}
clearSMSmemory();
smsnum = fona.getNumSMS();
if (smsnum == 0)
{
#ifdef MY_DEBUG
Serial.println(F("SMS Memory cleared"));
#endif
}
digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage LOW
}
///////////////////////////////////////////////////////
// the loop function runs over and over again forever
///////////////////////////////////////////////////////
void loop()
{
blipled();
// sensor.request(SMSTEXT, V_TEXT, 0);
wait(500); // wait for a second and proces messages
#ifdef MY_DEBUG
Serial.print(F("Owner's number: "));
Serial.println(myOwnersNumber);
Serial.print(F("Last received number: "));
Serial.println(ReceivedNumber);
#endif
smsnum = fona.getNumSMS();
if (smsnum < 0)
{
#ifdef MY_DEBUG
Serial.println(F("Could not read # SMS"));
#endif
}
#ifdef MY_DEBUG
Serial.println(F("Process incoming messages"));
#endif
if (MsgReceived && KnowMyOwner)
{
// a node sent us V_TEXT and we know the owner, so we can send an SMS
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
if (fona.sendSMS(myOwnersNumber, smsbuffer))
{
// SMS was sent to owner
MsgReceived = false;
strcpy(smsbuffer, "");
strcpy(msgbuffer, "");
}
else
{
// We do not know the owner, then ignore this message, we know the owner but no message was received, so just to be safe:
MsgReceived = false;
strcpy(msgbuffer, "");
}
}
if (smsnum > 0)
{ // we received an SMS and now need to check it
#ifdef MY_DEBUG
Serial.print(smsnum);
Serial.println(F(" SMS received"));
#endif
if (! fona.readSMS(smsnum, smsbuffer, MAXSMSLENGTH, &smslen))
{ // could not read SMS
#ifdef MY_DEBUG
Serial.println(F("Failed to get SMS!"));
#endif
}
else
{ // We could read the SMS, now retreive sms to smsbuffer and number of origin
fona.getSMSSender(smsnum, ReceivedNumber, MAXNUMBERLENGTH);
#ifdef MY_DEBUG
Serial.print(F("***** SMS #")); Serial.print(smsnum);
Serial.print(F(" (")); Serial.print(smslen); Serial.println(F(") bytes *****"));
Serial.println(smsbuffer);
Serial.print(F("from: "));
Serial.println(ReceivedNumber);
Serial.println(F("***************************"));
Serial.print(F("Owner is known: "));
if (KnowMyOwner)
Serial.println(F("yes"));
else
Serial.println(F("no"));
Serial.println();
#endif
if (!KnowMyOwner)
{ // no owner, so check request for ownership
if (strcmp(smsbuffer, MYPASSWORD) == 0)
{ // valid question for ownership
strcpy(smsbuffer, "OwnReq by: ");
strcat(smsbuffer, ReceivedNumber);
send(SMSMsg.set(smsbuffer));
KnowMyOwner = true;
strcpy(myOwnersNumber, ReceivedNumber);
// from now on we can respond to owner
#ifdef MY_DEBUG
Serial.print(F("Request for ownership by "));
Serial.println(myOwnersNumber);
#endif
strcpy(smsbuffer, CONFIRMOWNER);
if (fona.sendSMS(myOwnersNumber, smsbuffer))
{ // send confirmation to new owner
strcpy(smsbuffer, "Owner is informed.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
#ifdef MY_DEBUG
Serial.print(smsbuffer);
Serial.print(": ");
Serial.println(myOwnersNumber);
#endif
}
else
{ // could not send confirmation to new owner
strcpy(smsbuffer, "Owner is not informed.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
}
strcpy(smsbuffer, "");
}
else
{ // no owner and no valid request, so ignore and log in controller
strcpy(smsbuffer, "Attempt by: ");
strcat(smsbuffer, ReceivedNumber);
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
strcpy(smsbuffer, "");
}
}
if (KnowMyOwner)
{ // now we can accept SMS messages but we need to check the origin of the SMS
if (strcmp(myOwnersNumber, ReceivedNumber) == 0)
{ // this is the owner talking, so handle his SMS
#ifdef MY_DEBUG
Serial.println();
Serial.print(F("Owner is talking: "));
Serial.println(smsbuffer);
Serial.println();
#endif
if (strcmp(smsbuffer, MYRELEASEWORD) == 0)
{
strcpy(smsbuffer, "Released by ");
strcat(smsbuffer, ReceivedNumber);
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
strcpy(smsbuffer, "I am released.");
if (fona.sendSMS(myOwnersNumber, smsbuffer))
{
strcpy(smsbuffer, "Owner is informed.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
}
else
{
strcpy(smsbuffer, "Owner is not informed.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
}
// clean up buffers, we are done and need to get ready for new owner request, ignore further messages
KnowMyOwner = false;
MsgReceived = false;
strcpy(myOwnersNumber, "");
strcpy(ReceivedNumber, "");
strcpy(smsbuffer, "");
strcpy(msgbuffer, "");
}
if (strcmp(smsbuffer, "Blip") == 0)
{ // handle the command to light the defaultled. This could be anything else of course
digitalWrite(defaultledpin, HIGH); // turn the LED on (HIGH is the voltage level)
wait(2000); // wait for two seconds
digitalWrite(defaultledpin, LOW); // turn the LED off by making the voltage LOW
strcpy(smsbuffer, "R: Blip");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
strcpy(smsbuffer, "");
}
// and here we put the code to pass the message on to another node
// smsbuffer contains the first 30 characters of the SMS received.
// if a message starts with Nxxx:1234567890123456789012345 then you need to pass on the content to node Nxxx
// the node needs to be able to handle the incoming V_TEXT message
if (IsAddressingNode()) // check if sms is in Node addressing format
{
int NodeID = GetNodeID();
#ifdef MY_DEBUG
Serial.println();
Serial.print("Message for node ");
Serial.print(NodeID);
Serial.print(" is treated: ");
Serial.println(GetMessageContent(smsbuffer));
Serial.println();
#endif
// send a copy of the incoming message to the controller
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
// send the stripped message to the addressed node
SMSMsg.setDestination(NodeID);
SMSMsg.set(GetMessageContent(smsbuffer));
send(SMSMsg);
strcpy(smsbuffer, "");
}
// finally we mention to the controller all the SMS messages we received and did not treat.
if (strcmp(smsbuffer, "") != 0)
{ // so we still got something to do
#ifdef MY_DEBUG
Serial.println(smsbuffer);
Serial.println();
#endif
//strcpy(smsbuffer, "Received crap from owner.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
strcpy(smsbuffer, "");
}
}
else
{ // not the owner trying to get access
strcpy(smsbuffer, "Hack by:");
strcat(smsbuffer, ReceivedNumber);
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
#ifdef MY_DEBUG
Serial.print(F("Hijack attempt by: "));
Serial.println(ReceivedNumber);
#else
if (fona.sendSMS(myOwnersNumber, smsbuffer))
{
strcpy(smsbuffer, "Owner is informed.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
}
else
{
strcpy(smsbuffer, "Owner could not be informed.");
SMSMsg.setDestination(GATEWAY_ID);
send(SMSMsg.set(smsbuffer));
}
#endif
}
}
}
clearSMSmemory();
}
}