/* Hangar Cellphone heater control BB - 2015 Uses Adafruit FONA 800 Cellular Module Shield http://www.adafruit.com/products/2468 TTL serial communications with module Shield has Vio wired to 5V and Key wired to ground Software serial communicates with FONA module at 19200 baud SMS communications limited to 140 characters '\0' terminator must be appended to char sent to SMS for sending - The toCharArray does this as long as array is +1 size of string - Finally used just string and avoided problems using char AT Commands to set TA operating modes: This sets FONA clock to network time and writes to memory before installation AT+CLTS=1 AT&W AT+CCLK? to check time is set AT+CNMI=2,1,0,0,0 to Pass SMS notice via CMTI unsolicited message and store text on SIM card ==> CMTI "SM", 1 Interface to Arduino for FONA800: Vio to 5V GND to GND Key to GND (always on) RX to D2 TX to D3 (9 on Leo/Micro, 10 on Mega) RST to 4 Signals: PS - Power Status NS - Network Status Reset - 100ms low to reset RI - Ring Indicator // read and reply to SMS using callerid int8_t smsnum = fona.getNumSMS(); fona.getSMSSender(smsnum, replybuffer, 12); //get sender # char sender[13]; strncpy(sender, replybuffer, 13); //copy replybuffer to sender Serial.println(sender); AT commands: Enables local timestamp: AT+CLTS=1 AT&W */ /* SMS Text Message Commands: ON - Turn on relay OFF - Turn off relay ONxxyyzz - Turn on relay at xx:yy for zz hours */ #include "Adafruit_FONA.h" #include "Time.h" // FONA communications #define FONA_RX 2 #define FONA_TX 3 #define FONA_RST 4 #define TH1_PIN A0 // Temperature pin #define HEAT_PIN 11 // Heater control pins #define TIMER_PIN 12 // Pin for Timer Function ON LED indicator char replybuffer[255]; // this is a large buffer for replies String SMScmd; // string version of replybuffer[] String SMSreply; // SMS reply string to be sent back to caller String SMSstatus; // Status of controller int Thi; // High temperature int Tlo; // Low temperature time_t ThiTime; // High temperature time time_t TloTime; // Low temperature time String sCode; // Access code boolean bTimer = false; // Timer function on/off uint8_t tStartHr; // Start time of timer uint8_t tStartMin; // Start minute of timer uint8_t tStopHr; // Calculated stop hour for timer uint8_t tDur; // Number of hours duration for the timer // Setup serial ports #include SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); SoftwareSerial *fonaSerial = &fonaSS; Adafruit_FONA fona = Adafruit_FONA(FONA_RST); uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0); void setup() { Serial.begin(19200); // Start Arduino serial comm with UNO Serial.println(F("FONA SMS Controller")); Serial.println(F("Init....(May take 3 seconds)")); pinMode(HEAT_PIN,OUTPUT); // Heater pin mode pinMode(TIMER_PIN,OUTPUT); // Timer LED indicator // Start serial connection with FONA shield // 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); // AT+GSN command if (imeiLen > 0) { //Serial.print(F("SIM IMEI: ")); Serial.println(imei); } //Serial.println(F("FONA Ready")); // Set FONA to get time from cell system // Set temperature hi/lo to current temperature and time int ThermF = .19 * analogRead(TH1_PIN)-13.8; //Serial.println(ThermF); Thi=ThermF; Tlo=ThermF; ThiTime=now(); TloTime=now(); // Enable network time sync //fona.enableNetworkTimeSync(true); // AT+CLTS=1 command SMSstatus = StatusText(); // Make status text and set time // Check if time.h is set //if (timeStatus() == timeNotSet) { Serial.println(F("not set")); } //if (timeStatus() == timeNeedsSync) { Serial.println(F("not syncd")); } //if (timeStatus() == timeSet) { Serial.println(F("set")); } // timeStatus=2 for set Serial.println(SMSstatus); // int8_t nsms; // nsms = fona.getNumSMS(); // Serial.println("#:" + nsms); // Test pins to verify operation on power up // Confirm successful setup by both LEDs on for 2 seconds and relay clicking digitalWrite(HEAT_PIN,HIGH); digitalWrite(TIMER_PIN,HIGH); delay(2000); digitalWrite(HEAT_PIN,LOW); digitalWrite(TIMER_PIN,LOW); // Serial print number of SMSs on SIM card for troubleshooting, should be zero int8_t smsnum = fona.getNumSMS(); //Serial.print(smsnum); Serial.println(F(" SMS's")); Blink(2); // Blink Timer LED } // end setup char fonaInBuffer[64]; //for notifications from the FONA void loop() { char* bufPtr = fonaInBuffer; // fona buffer pointer Blink(1); // heartbeat blink to show loop is working TempHiLo(); // check for new high or low temperature // Look for FONA SMS data if (fona.available()) //any data available from the FONA? { //Serial.println(F("SMS data received")); 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(5); // initally 1 ms (4800 baud = 1.67ms/byte) } while ((*bufPtr++ != '\n') && (fona.available()) && (++charCount < (sizeof(fonaInBuffer)-1))); //Add a terminal NULL to the notification string *bufPtr = 0; //Serial.print(F("Char count:")); //Serial.println(charCount); //Serial.print(F("InBuffer:")); //Serial.println(String(fonaInBuffer)); // SMS received notification +CMTI // Scan the notification string // If it's an SMS message, we'll get the slot number in 'slot' if (1 == sscanf(fonaInBuffer, "+CMTI: \"SM\",%d", &slot)) { //Serial.print(F("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(F("No SMS message in slot, so no sender info!")); } //Serial.print(F("From: ")); //Serial.println(callerIDbuffer); // Get SMS message from slot uint16_t smslen; smslen=140; boolean bSMS = fona.readSMS(slot, replybuffer, 250, &smslen); if (bSMS == true) { // Peform operation based on message SMScmd = String(replybuffer); // Convert replybuffer char to String SMScmd.toUpperCase(); // Change message to Uppercase SMScmd.trim(); // Trim off spaces //Serial.print(F("Cmd:")); //Serial.println(SMScmd); // Check command message received // Check for three character access code at beginning of text message if (SMScmd.substring(1,3)==sCode) {} // code for checking access goes here when added // Reset reply message SMSreply=""; // Reset reply string and start is here // Check for ON/OFF command if (SMScmd == F("OFF")) { // Look for OFF command digitalWrite(HEAT_PIN,LOW); // Turn off heater SMSreply = F("Heat off, "); // Reply message bTimer = false; // Shut down timer if on digitalWrite(TIMER_PIN, LOW); //Serial.println(F("Heat & Timer off")); } if (SMScmd.indexOf("ON") == 0) { // Look for ON command in string if (SMScmd.length() == 2) { // Look for only "ON" command // Only ON command sent // Turn on heater, no timer digitalWrite(HEAT_PIN,HIGH); tStartHr = hour(); tStartMin = minute(); SMSreply = F("Heat on, "); bTimer = false; digitalWrite(TIMER_PIN, LOW); //Serial.println(F("Heat on")); } else { // More than just ON - Get start time and duration // Command format example: "ON083004" On at 0830 for 4 hours digitalWrite(HEAT_PIN,LOW); // start by turning heater off tStartHr = SMScmd.substring(2,4).toInt(); // hour to start if (tStartHr<0 || tStartHr>23) {tStartHr=7;} tStartMin = SMScmd.substring(4,6).toInt(); // minute to start if (tStartMin<0 || tStartMin>59) {tStartMin=0;} tDur = SMScmd.substring(6,8).toInt(); // Hours to run if (tDur<0) {tDur=1;} // No shorter than one hour if (tDur>6) {tDur=1;} // No longer than 6 hours tStopHr = tStartHr + tDur; // Hour to stop if (tStopHr>23) {tStopHr=tStopHr-24;} // Start reply text SMSreply = F("Timer Set to: "); SMSreply += String(tStartHr) + F(":") + String(tStartMin) + F(" for ") + String(tDur) + F("hr "); bTimer = true; digitalWrite(TIMER_PIN, HIGH); //Serial.println(SMSreply); } //end else } // end of looking for ON/OFF command // Check for Status request if (SMScmd == "S") { SMSreply = F("Status: "); //Serial.println(F("Status cmd")); } // Delete received SMS command message // Not needed now that the command has been received //Serial.println(F("Delete msg")); fona.deleteSMS(slot); fona.deleteSMS(0); // Ensure there are at least three open SMS slots fona.deleteSMS(1); fona.deleteSMS(2); delay(1000); // Check if there was a valid command that set a SMSreply message if (SMSreply != "") { //Send back an automatic response, SMSreply //Serial.println(F("Sending SMS...")); SMSstatus = StatusText(); // Make status text for reply SMSreply += SMSstatus; // Append SMSstatus to reply int replylen=SMSreply.length(); // Get length of SMS message char SMSdata[replylen+1]; // Set char array size SMSreply.toCharArray(SMSdata,replylen+1); // Convert string SMSreply to char //Serial.print(F("SMSreply: ")); //Serial.println(SMSreply); //Serial.print(F("SMSlen: ")); //Serial.println(replylen); if (!fona.sendSMS(callerIDbuffer, SMSdata)) { // Send SMS message //Serial.println(F("Failed")); } else { //Serial.println(F("Sent!")); } } // end Send reply } // end Get SMS message //fona.sendSMS("YOUR PHONE NUMBER", "FONA received text"); // Test only test int8_t smsnum = fona.getNumSMS(); //Serial.print(smsnum); Serial.println(F(" SMS's")); // Show # SMSs } // end SMS received //Blink(4); //Serial.println(StatusText()); } // end fona available // Timer routine // Check if timer is on and whether to turn heater on or off if (bTimer == true) { // check time to turn on or off heater // check if already on if (digitalRead(HEAT_PIN)==1) { // Heat already on // Check for off time if (hour() == tStopHr && minute() == tStartMin) { digitalWrite(HEAT_PIN, LOW); bTimer = false; // Turn off timer digitalWrite(TIMER_PIN, LOW); //Serial.print(F("Timer Off @")); //Serial.print(hour()); //Serial.println(minute()); } } // Heater off, check time to turn on else { // get time / compare time to start heater if (hour() == tStartHr && minute() == tStartMin) { // turn heater on digitalWrite(HEAT_PIN,HIGH); //Serial.print(F("Timer On @")); //Serial.print(hour()); //Serial.println(minute()); } } // end else } // end Timer } // end main loop // - - - - - - Subroutines - - - - - - - String StatusText() { // create system status text to send back as SMS reply //String(stat); String stat; char tbuff[16]; // set clock and tell time setCellTime(); stat = F("At "); sprintf(tbuff, "%02d", hour()); stat += tbuff; stat += F(":"); sprintf(tbuff, "%02d", minute()); stat += tbuff; // Show battery status: mV and % stat += F(" B:"); uint16_t vbat; fona.getBattVoltage(&vbat); stat += vbat; stat += F("mV "); fona.getBattPercent(&vbat); stat += vbat; // Show Signal Strength stat += F("% S:"); uint8_t n = fona.getRSSI(); stat += -113 + (2 * n); stat += F("dbm "); /* Adding time string from FONA is problematic, extra characters fowl string char buffer[23]; fona.getTime(buffer, 23); stat += buffer; */ // Get thermistor temperature reading int ThermF = .19 * analogRead(TH1_PIN)-13.8; stat += F("Temp: "); stat += ThermF; stat += F("F "); // Show high / low temperatures in last 24 hours stat += F("Lo:"); stat += Tlo; stat += F("F @"); stat += hour(TloTime); stat += ":"; stat += minute(TloTime); stat += F(" Hi:"); stat += Thi; stat += F("F @"); stat += hour(ThiTime); stat += ":"; stat += minute(ThiTime); // Timer status stat += F(" Timer:"); if (bTimer == true) { stat += F("ON"); stat += F(" Start:"); stat += tStartHr; stat += F(":"); stat += tStartMin; stat += F(" End:"); stat += tStopHr; stat += F(":"); stat += tStartMin; } else { (stat+= F("OFF")); } // Heater status stat += F(" Heater:"); //stat += digitalRead(HEAT_PIN); if (digitalRead(HEAT_PIN)==1) { stat += F("ON"); // Only show turned on time if Timer is not active if (bTimer==false) { stat += F("@"); stat += tStartHr; stat += F(":"); stat += tStartMin; } } else {stat += F("OFF");} return stat; } void setCellTime() { // Get time from FONA and parse out time // Use FONA time to set UNO in time.h int h, m, d, mon, y; char tbuffer[23]; //Serial.println(F("Setting time")); fona.getTime(tbuffer, 23); // Format: "mm/dd/yy,hh:mm:ss:xx+xx" quotes part of string mon = String(tbuffer).substring(1,3).toInt(); d = String(tbuffer).substring(4,6).toInt(); y = String(tbuffer).substring(7,9).toInt(); h = String(tbuffer).substring(10,12).toInt(); m = String(tbuffer).substring(13,15).toInt(); setTime(h,m,0,d,mon,y); // int h,m,s,d,m,y } void Blink(uint8_t blinks) { // Blink Timer LED // Quickly blink the !bState boolean bState; // Save initial state bState = digitalRead(TIMER_PIN); for (uint8_t i=1; i<=blinks; i++) { digitalWrite(TIMER_PIN,!bState); delay(20); digitalWrite(TIMER_PIN,bState); delay(600); } } void TempHiLo() { // Capture high and low temperatures in the last 24 hours // Only perform once per minute if (second() <= 1) { // Curve fit for the thermistor attached to TH1_PIN to get temperature in degrees F int temp= .19 * analogRead(TH1_PIN)-13.8; //Serial.println(temp); // Can't get accurate time during Setup() // Correct it here to present time if (ThiTime<100) {ThiTime=now();} if (TloTime<100) {TloTime=now();} // Get current time, tm time_t tm=now(); // Seconds since 1.1.1970 // Check for new high or low over last 24 hours (5,184,000 sec) if (temp > Thi && tm-ThiTime<5184000) {Thi=temp; ThiTime=tm; } if (temp < Tlo && tm-TloTime<5184000) {Tlo=temp; TloTime=tm; } // Diagonostics for troubleshooting /* Serial.print("@"); Serial.print(hour(tm)); Serial.print(minute(tm)); Serial.print(F(" Lo:")); Serial.print(Tlo); Serial.print(F("F @")); Serial.print(hour(TloTime)); Serial.print(":"); Serial.print(minute(TloTime)); Serial.print(F(" Hi:")); Serial.print(Thi); Serial.print(F("F @")); Serial.print(hour(ThiTime)); Serial.print(":"); Serial.println(minute(ThiTime)); */ } }