Open_Auto.ino-1d87fae9/Open_Auto.ino
2018-03-26 01:12:56 +02:00

468 lines
No EOL
14 KiB
C++

// This #include statement was automatically added by the Particle IDE.
#include <Particle-GPS.h>
// This #include statement was automatically added by the Particle IDE.
#include <ParticleSoftSerial.h>
#include "Particle.h"
//This is licensed under GPL V3.
#define RECEIVER SoftSer
#define PROTOCOL SERIAL_8N1
const uint32_t baud = 9600;
//init GPS device on Serial1
Gps _gps = Gps(&Serial1);
//Create a 1ms timer to feed in the GPS data
Timer _timer = Timer(1, onSerialData);
//Pin assignments for the RFID reader
#define PSS_RX D3 // RX must be interrupt enabled (on Photon/Electron D0/A5 are not)
#define PSS_TX C5 //this pin isn't something we use, I couldn't find a null pin
ParticleSoftSerial SoftSer(PSS_RX, PSS_TX);
struct Reservation {
char UserID[9];
int StartDay;
int StartMonth;
int StartYear;
int StartHour;
int StartMinute;
int Duration;
};
//variable for RFID card reading process
char CARDcurrent[4];
//Pin asignments
int OpenRelay = D4;
int CloseRelay = D5;
int StatusLED = D7;
//boolean to track the door status; actually we'll only use it as a toggle.
bool DoorsOpenBool = false;
void clearEEPROM(); // forward declaration
int EEPROMctr = 0; //eeprom index
//Note that the 0th value of the EEPROM is used to store the number of reservations
//Values 1+ store reservations in blocks of 36 bytes.
int ReservationSize = 36; //number of bytes per reservation
//some strings that we'll use for system variables
String ReservationsTable;
String ValidGPSPosition;
//define a master RFID card that can always open/close the door regardless of reservation status (i.e. for pool manager)
String MasterRFIDCard = "983553fe";
class ReservationCmd {
String argument;
public:
void extractValues(String);
String UserIDStr (void) {
return argument.substring(argument.indexOf("UserID=")+7, argument.indexOf("StDy="));
}
int StartDayInt (void) {
return (argument.substring(argument.indexOf("StDy=")+5, argument.indexOf("StMon="))).toInt();
}
int StartMonInt (void) {
return (argument.substring(argument.indexOf("StMon=")+6, argument.indexOf("StYr="))).toInt();
}
int StartYearInt (void) {
return (argument.substring(argument.indexOf("StYr=")+5, argument.indexOf("StHr="))).toInt();
}
int StartHourInt (void) {
return (argument.substring(argument.indexOf("StHr=")+5, argument.indexOf("StMin="))).toInt();
}
int StartMinuteInt (void) {
return (argument.substring(argument.indexOf("StMin=")+6, argument.indexOf("Dur="))).toInt();
}
int DurationInt (void) {
return (argument.substring(argument.indexOf("Dur=")+4, argument.indexOf("f"))).toInt();
}
};
//
void ReservationCmd::extractValues (String stringPassed){
argument = stringPassed;
}
void DoorOpenFn()
{
digitalWrite(OpenRelay,HIGH);
delay(400);
digitalWrite(OpenRelay,LOW);
DoorsOpenBool = true;
}
void DoorCloseFn()
{
digitalWrite(CloseRelay,HIGH);
delay(400);
digitalWrite(CloseRelay,LOW);
DoorsOpenBool = false;
}
void StatusLEDFn()
{
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
}
void setup()
{
//set pin modes for hardwired devices
pinMode(OpenRelay, OUTPUT);
pinMode(CloseRelay, OUTPUT);
pinMode(StatusLED, OUTPUT);
//set these outputs correctly
digitalWrite(OpenRelay, LOW);
digitalWrite(CloseRelay, LOW);
digitalWrite(StatusLED, LOW);
//define functions
Particle.function("Open", OpenRelayCmd);
Particle.function("Close", CloseRelayCmd);
Particle.function("StatusLED", StatusLEDFlash);
//Particle.function("PubPosn", SendPosition); deprecated
Particle.function("MkResvn", ReserveString);
Particle.function("CanResvn", CancelString);
Particle.function("HomeBox", HomeCoords);
Particle.function("PubResvn", ShowReservations);
Particle.function("WipeResvn", WipeReservations);
//define variables
Particle.variable("CarResvn", ReservationsTable);
Particle.variable("CarPos", ValidGPSPosition);
//set up serial debug link
Serial.begin();
Serial.printlnf("ready for data");
//setup RFID reader soft serial
RECEIVER.begin(baud, PROTOCOL); // but SoftSerial can ;-)
//Init GPS
_gps.begin(9600);
_gps.sendCommand(PMTK_SET_NMEA_OUTPUT_ALLDATA);
_timer.start();
//initialise the EEPROM counter with the number of reservations that were in memory before poweroff.
EEPROM.get(0, EEPROMctr);
}
void onSerialData()
{
_gps.onSerialData();
}
void loop()
{
Serial.print("Data[0] = "); Serial.println(_gps.data[0]);
Serial.print("Data[1] = "); Serial.println(_gps.data[1]);
Serial.print("Data[2] = "); Serial.println(_gps.data[2]);
Serial.print("Data[3] = "); Serial.println(_gps.data[3]);
Serial.print("Data[4] = "); Serial.println(_gps.data[4]);
Serial.print("Data[5] = "); Serial.println(_gps.data[5]);
Serial.print("Data[6] = "); Serial.println(_gps.data[6]);
Rmc rmc = Rmc(_gps);
if (rmc.parse())
{
Serial.println("3) Recommended Minimum Navigation Information ($GPRMC)");
Serial.println("======================================================");
Serial.print("UTC Time: "); Serial.println(rmc.utcTime);
Serial.print("Latitude: "); Serial.println(rmc.latitude);
Serial.print("North/SouthIndicator: "); Serial.println(rmc.northSouthIndicator);
Serial.print("Longitude: "); Serial.println(rmc.longitude);
Serial.print("East/WestIndicator: "); Serial.println(rmc.eastWestIndicator);
Serial.print("Speed Over Ground: "); Serial.println(rmc.speedOverGround);
Serial.print("Course Over Ground: "); Serial.println(rmc.courseOverGround);
Serial.print("Date: "); Serial.println(rmc.date);
Serial.print("Magnetic Variation: "); Serial.print(rmc.magneticVariation); Serial.print(" "); Serial.println(rmc.magneticVariationDirection);
Serial.print("Mode: "); Serial.println(rmc.mode);
Serial.println("");
}
ValidGPSPosition = rmc.latitude + ";" + rmc.northSouthIndicator + ";" + rmc.longitude + ";" + rmc.eastWestIndicator + ";" + rmc.utcTime;
Serial.println(ValidGPSPosition);
int counter = 0;
unsigned long cardread = 0;
String cardpublish;
while (RECEIVER.available())
{
for (int cardident = 0; cardident < 5; cardident++) {
counter = (RECEIVER.read());
if (cardident > 0) Serial.print(int(counter), HEX);
CARDcurrent[cardident-1] = counter;
Serial.print(" ");
}
Serial.println("");
cardread=int(CARDcurrent[0]);
cardread=cardread << 8;
cardread=cardread+ int(CARDcurrent[1]);
cardread=cardread << 8;
cardread=cardread+ int(CARDcurrent[2]);
cardread=cardread << 8;
cardread=cardread+ int(CARDcurrent[3]);
Serial.println("card raw");
Serial.println(cardread, HEX);
cardpublish = String(cardread, HEX);
Serial.println("card string");
Serial.println(cardpublish);
bool success;
success = Particle.publish("RFIDident", String(cardread, HEX), 0, PUBLIC);
if (!success) {
Serial.println("failedtopublish"); // get here if event publish did not work
}
if (String(cardread, HEX)==MasterRFIDCard) {
Serial.println("match");
StatusLEDFn();
if (DoorsOpenBool) {
DoorCloseFn();
Serial.println("closing");
}
else
{
DoorOpenFn();
Serial.println("Opening");
}
}
}
RECEIVER.flush();
if (Particle.connected()) {
Serial.println("Connected!");
}
delay(1000);
}
int OpenRelayCmd(String command) {
/* Particle.functions always take a string as an argument and return an integer.
Since we can pass a string, it means that we can give the program commands on how the function should be used.
In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
Then, the function returns a value to us to let us know what happened.
In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
and -1 if we received a totally bogus command that didn't do anything to the LEDs.
*/
if (command=="on") {
DoorOpenFn();
return 1;
}
else {
return -1;
}
}
int CloseRelayCmd(String command) {
/* Particle.functions always take a string as an argument and return an integer.
Since we can pass a string, it means that we can give the program commands on how the function should be used.
In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
Then, the function returns a value to us to let us know what happened.
In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
and -1 if we received a totally bogus command that didn't do anything to the LEDs.
*/
if (command=="on") {
DoorCloseFn();
return 1;
}
else {
return -1;
}
}
int StatusLEDFlash(String command) {
/* Particle.functions always take a string as an argument and return an integer.
Since we can pass a string, it means that we can give the program commands on how the function should be used.
In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
Then, the function returns a value to us to let us know what happened.
In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
and -1 if we received a totally bogus command that didn't do anything to the LEDs.
*/
if (command=="on") {
StatusLEDFn();
return 1;
}
else {
return -1;
}
}
/*
//deprecated
int SendPosition(String command){
if (command=="on") {
//flash the led
StatusLEDFn();
ValidGPSPosition = _gps.data[4];
return 1;
}
else {
return -1;
}
}
*/
int ReserveString(String mssgArgs){
Serial.println("command recieved...");
Serial.println(mssgArgs);
//oldData = false;
//lastDataTransmitTime = millis();
ReservationCmd command;
command.extractValues(mssgArgs);
Serial.println("Valid Reservation Recieved...");
Serial.print("UserID: ");
Serial.println(command.UserIDStr());
Serial.println("Start Day = ");
Serial.println(command.StartDayInt());
Serial.println("Start Month = ");
Serial.println(command.StartMonInt());
Serial.println("Start Year = ");
Serial.println(command.StartYearInt());
Serial.println("Start Hour = ");
Serial.println(command.StartHourInt());
Serial.println("Start Minute = ");
Serial.println(command.StartMinuteInt());
Serial.println("Duration = ");
Serial.println(command.DurationInt());
// updateVariables(i, command.mssgText(), command.mssgValue0(), command.mssgValue1()); // Pass decoded variables to function
// badMessage = false;
return 1;
}
int CancelString(String command){
if (command=="on") {
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
return 1;
}
else {
return -1;
}
}
int HomeCoords(String command){
if (command=="on") {
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
return 1;
}
else {
return -1;
}
}
int ShowReservations(String command){
if (command=="on") {
digitalWrite(StatusLED,HIGH);
delay(1000);
digitalWrite(StatusLED,LOW);
return 1;
}
else {
return -1;
}
}
int WipeReservations(String command) {
if (command=="on") {
//flash the LED
StatusLEDFn();
//Wipe the EEPROM
clearEEPROM();
//Reset the onboard reservation counter to 0 (assuming EEPROM is wiped)
EEPROM.get(0, EEPROMctr);
return 1;
}
else {
return -1;
}
}
Reservation CreateReservation(String CUserID, int CStartDay, int CStartMonth, int CStartYear, int CStartHour, int CStartMinute, int CDuration)
{
//make a buffer for the reservation
Reservation CreateResvn;
//transfer the data from the function - there's probably a better way to do the string transfer
CreateResvn.UserID[0] = CUserID[0];
CreateResvn.UserID[1] = CUserID[1];
CreateResvn.UserID[2] = CUserID[2];
CreateResvn.UserID[3] = CUserID[3];
CreateResvn.UserID[4] = CUserID[4];
CreateResvn.UserID[5] = CUserID[5];
CreateResvn.UserID[6] = CUserID[6];
CreateResvn.UserID[7] = CUserID[7];
CreateResvn.StartDay = CStartDay;
CreateResvn.StartMonth = CStartMonth;
CreateResvn.StartYear = CStartYear;
CreateResvn.StartHour = CStartHour;
CreateResvn.StartMinute = CStartMinute;
CreateResvn.Duration = CDuration;
//send the created variable back
return CreateResvn;
}
int AddReservation(Reservation ReservationToAdd)
{
//work out the next free spot and put it in that reservation
EEPROM.put(((EEPROMctr*ReservationSize)+1), ReservationToAdd);
EEPROMctr++;
return EEPROMctr;
}
void RecallReservation(int ResvnNumber)
{
//Create a buffer to store the recalled data
Reservation RetRes;
//extract it from the EEPROM
EEPROM.get((((ResvnNumber-1)*ReservationSize)+1), RetRes);
//Now format it as a string
const int STRING_BUF_SIZE = 9;
char stringBuf[STRING_BUF_SIZE];
stringBuf[sizeof(stringBuf) - 1] = 0; // make sure it's null terminated
// Initialize a String object from the buffer
String str(stringBuf);
str = String(RetRes.UserID);
//Print it out
Serial.printlnf("ReservationNum=%d, UserID=%s, Day=%d, Month=%d, Year=%d, Hour=%d, Minute=%d, Duration=%d, sizeof(RetRes)=%d", ResvnNumber, str.c_str(), RetRes.StartDay, RetRes.StartMonth, RetRes.StartYear, RetRes.StartHour, RetRes.StartMinute, RetRes.Duration, sizeof(RetRes));
}
void clearEEPROM() {
for(int addr = 0; addr < 256; addr++) {
EEPROM.write(addr, 0);
}
}