// RemoteRelay.ino // Takes commands from Particle App on iPhone // Commands: on, off, set, start time, stop time // Status of relay read in Variables tab on App // Console is at: // https://console.particle.io/devices/e00fce68c3f933a3d58eca9f // Console events are not captured in history, only real time // Console events show anything published but only if console is running // https://console.particle.io/events #include "Particle.h" #include "Arduino.h" #include #include "Adafruit_DHT.h" SerialLogHandler logHandler; // Sends log.xxx messages to connected USB device // Run in Terminal: "Particle Serial Monitor --follow" to view // Or, use Arduino Serial Monitor, requires reconnect after flashing #define ONE_DAY_MILLIS (24 * 60 * 60 * 1000) unsigned long lastSync = millis(); // Last time UTC was syncd unsigned long lastUTCupdate = millis(); // Last time UTC was updated unsigned long lastVupdate = millis(); // Last time voltage variables were updated #define DHTPIN D4 // Uncomment whatever type you're using! //#define DHTTYPE DHT11 // DHT 11 #define DHTTYPE DHT22 // DHT 22 (AM2302) //#define DHTTYPE DHT21 // DHT 21 (AM2301) DHT dht(DHTPIN, 22); const int RELAY_PIN = D2; const int LED_PIN = D7; // Set program variables String RelayState; // Rely State variable (ON/OFF) String TimerStatus; // Timer function status String UTCtime; // UTC variable, only used to verify time int StartTime; // Time to turn on relay int StopTime; // Time to turn off relay float TimeOffset; // DST time offset int StartHr; // timer start hour int StartMin; // timer start minute int StopHr; // timer stop hour int StopMin; // timer stop minute String V33; // V3.3 voltage int V33_PIN=A0; // V3.3 measurement pin String Vlipo; // LiPo voltage String Vusb; // Voltage from wall power supply, resistor divider: 4.71V = 2.33V = 2930counts int Vusb_PIN = A2; // Divider connected to +5 to give status of wall power String USBpwr="OFF"; // Current state of Vusb power int TempF; // Temperature in deg F int Humid; // Humidity percent String s_lostUSB; // Last time USB power was lost or power applied String sSoc; // State of charge of LiPo String sVersion; // Build version FuelGauge fuel; // Battery instance String cellSig; // Cellular signal level //PMIC power; // Power instance void setup() { Serial.begin(); // Serial monitor dht.begin(); // Start DHT sensor Serial.print("RemoteRelay"); Serial.print("3 Oct 2021"); sVersion = __DATE__ " " __TIME__; pinMode(RELAY_PIN, OUTPUT); // Relay pin digitalWrite(RELAY_PIN, LOW); // Turn off relay RelayState="OFF"; TimerStatus="OFF"; pinMode(LED_PIN, OUTPUT); // On-board LED pin digitalWrite(LED_PIN, LOW); // Turn off LED - this is used to indicate relay on/off // Set the displayed console functions //Particle.function("SetRelay", RelayFunction); // Commands ON/OFF/SET Particle.function("Relay ON", RelayOn); // Call to turn relay on - No input string required Particle.function("Relay OFF", RelayOff); // Call to turn relay off - No input string required Particle.function("Timer ON", TimerOn); // Call to turn timer on - No input string required Particle.function("Timer OFF", TimerOff); // Call to turn timer off - No input string required Particle.function("StartUTC", startFunction); // Start time function entry Particle.function("StopUTC", stopFunction); // Stop time function entry System.on(button_click, buttonHandler); // Register the button handler for button_click event // Set the displayed contole variables Particle.variable("RelayStatus", &RelayState, STRING); // Relay ON or OFF Particle.variable("UTC Start", &StartTime, INT); // Timer start time in UTC Particle.variable("UTC Stop", &StopTime, INT); // Timer stop time in UTC Particle.variable("Timer", &TimerStatus, STRING); // Timer ON or OFF Particle.variable("UTC Now", &UTCtime, STRING); // Current UTC Particle.variable("Vusb", &Vusb, STRING); // USB power voltage Particle.variable("Vlipo", &Vlipo, STRING); // LiPo voltage Particle.variable("V3.3", &V33, STRING); // 3V3 voltage Particle.variable("USBpwr", &USBpwr, STRING); // ON or OFF Particle.variable("Temp F", &TempF, INT); // DHT temperature in deg F Particle.variable("Humid %", &Humid, INT); // DHT humidity Particle.variable("Ulost", &s_lostUSB, STRING); // Last time that USB power was applied Particle.variable("SoC %", &sSoc, STRING); // LiPo state of charge Particle.variable("Ver", &sVersion, STRING); // Build version date Particle.variable("Signal", &cellSig, STRING); // Cellular signal level TimeOffset = Time.getDSTOffset(); // -4 for EST - Not used UTCtime = Time.timeStr(); // Current UTC s_lostUSB = Time.timeStr(); // Put start time in USB power lost variable //UTCtime = String(Time.hour()) + ":" + String(Time.minute()); //power.begin(); // For charge voltage getVoltages(); // Get voltage measurements Log.info("Started @ " + Time.timeStr()); // Log restart time to serial monitor TempF = int(dht.getTempFarenheit()); // Get temperature Humid = int(dht.getHumidity()); //Particle.publishVitals(); // Publish vitals } void loop() { // Check for time to turn on or off // Look for TimerStatus ON then check whether to turn relay on or off if (TimerStatus=="ON") { int nowHr=Time.hour(); int nowMin=Time.minute(); if (nowHr==StartHr && nowMin==StartMin) { if (RelayState=="OFF") { // Only do this once // Turn on relay based on timer digitalWrite(RELAY_PIN, HIGH); digitalWrite(LED_PIN, HIGH); RelayState = "ON"; Particle.publish("Relay", RelayState, PRIVATE); Log.info("Relay ON"); delay(1000); TimerStatus="Running"; Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Timer Running"); } } } if (TimerStatus=="Running") { int nowHr=Time.hour(); int nowMin=Time.minute(); if (nowHr==StopHr && nowMin==StopMin) { if (RelayState=="ON") { // Only do this once // Turn off relay digitalWrite(RELAY_PIN, LOW); digitalWrite(LED_PIN, LOW); RelayState="OFF"; Particle.publish("Relay", RelayState, PRIVATE); Log.info("Relay OFF"); delay(1000); TimerStatus="OFF"; Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Timer OFF"); } } } if (millis() - lastSync > 60*60*1000) { //Request time synchronization from the Particle Device Cloud once per hour Particle.syncTime(); lastSync = millis(); Log.info("Device Cloud Sync UTC"); } if (millis() - lastUTCupdate > 300000) { // Once every 5 minutes // Update UTC lastUTCupdate=millis(); UTCtime = Time.timeStr(); // Update UTCtime variable Log.info("Time.timeStr Update") } if (millis() - lastVupdate > 300000) { // Once every 5 minutes // Update voltage measurements lastVupdate=millis(); getVoltages(); // Update voltage variables // Update Cellular Signal Strength CellularSignal sig = Cellular.RSSI(); float signal = sig.getStrength(); cellSig = String(signal, 0); Log.info("Cellular signal strength: %.02f%%", sig.getStrength()); } } // End of loop // *** Functions *** int RelayOn(String cmd) { // Manual relay control, Relay ON, Timer OFF digitalWrite(RELAY_PIN, HIGH); digitalWrite(LED_PIN, HIGH); RelayState = "ON"; Particle.publish("Relay", RelayState, PRIVATE); Log.info("Relay ON"); delay(1000); TimerStatus="OFF"; Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Timer OFF"); return 0; } int RelayOff(String cmd) { digitalWrite(RELAY_PIN, LOW); // Turn off Relay digitalWrite(LED_PIN, LOW); RelayState="OFF"; Particle.publish("Relay", RelayState, PRIVATE); Log.info("Relay OFF"); delay(1000); TimerStatus="OFF"; // Turn off Timer Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Timer OFF"); return 0; } int TimerOn(String cmd) { // Check for valid time values before turning on if ((StartTime >0) && (StartTime <2359) && (StopTime >0) && (StopTime <2359) ) { StartHr = int(StartTime/100); StartMin = StartTime - StartHr*100; StopHr = int(StopTime/100); StopMin = StopTime - StopHr*100; TimerStatus="ON"; Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Timer ON"); Serial.print("Start @ "); Serial.print(StartHr); Serial.print(":"); Serial.println(StartMin); Serial.print("Stop @ "); Serial.print(StopHr); Serial.print(":"); Serial.println(StopMin); } return 0; } int TimerOff(String cmd) { RelayOff("X"); // Call RelayOff function, turns off relay and timer return 0; } /* int RelayFunction(String cmd) { cmd = cmd.toUpperCase(); // Comvert cmd to upper case if (cmd.equals("ON")) { digitalWrite(RELAY_PIN, HIGH); digitalWrite(LED_PIN, HIGH); RelayState = "ON"; Particle.publish("Relay", RelayState, PRIVATE); TimerStatus="OFF"; delay(1000); Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Relay ON"); } if (cmd.equals("OFF")) { digitalWrite(RELAY_PIN, LOW); digitalWrite(LED_PIN, LOW); RelayState="OFF"; Particle.publish("Relay", RelayState, PRIVATE); TimerStatus="OFF"; delay(1000); Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Relay OFF"); } if (cmd.equals("SET")) { // Check for valid time values before turning on if ((StartTime >0) && (StartTime <2359) && (StopTime >0) && (StopTime <2359) ) { StartHr = int(StartTime/100); StartMin = StartTime - StartHr*100; StopHr = int(StopTime/100); StopMin = StopTime - StopHr*100; TimerStatus="ON"; Particle.publish("Timer", TimerStatus, PRIVATE); Log.info("Timer Set"); Serial.print("Start @ "); Serial.print(StartHr); Serial.print(":"); Serial.println(StartMin); Serial.print("Stop @ "); Serial.print(StopHr); Serial.print(":"); Serial.println(StopMin); } } return 0; } */ void buttonHandler(system_event_t event, int data) { String evtData; evtData = "Button: "; evtData += data; //evtData += data.toString(); Log.info(evtData); } int startFunction(String scmd) { int cmd=scmd.toInt(); // Convert cmd to an integer if ((cmd >0) && (cmd <2359) ) { // Check hour StartHr = int(cmd/100); // Get hour StartMin = cmd - StartHr*100; // Get minutes if (StartMin>59) {StartMin=59;} // Limit minutes to 59 StartTime= StartHr*100 + StartMin; // Reassemble as hhmm for timer and display Log.info("Start UTC: " + StartHr + StartMin); } return 0; } int stopFunction(String scmd) { int cmd=scmd.toInt(); if ((cmd >0) && (cmd <2359) ) { StopHr = int(cmd/100); StopMin = cmd - StopHr*100; if (StopMin>59) {StopMin=59;} StopTime= StopHr*100 + StopMin; Log.info("Stop UTC: " + StopTime); } return 0; } void getVoltages() { // Calculate Voltages, get temperature & humidity // USB measured with resistor divider factor of 2.02 // 3.27 is measured 3.3V board voltage int iADC = analogRead(Vusb_PIN); float vADC = iADC * 3.28 * 2.02 / 4096; Vusb = String(vADC,2); // 2 decimal places Log.info("Vusb: " + Vusb); // calculated voltage if (vADC > 3 && USBpwr=="OFF") { // Add event that USB power came on USBpwr="ON"; //Particle.publish("USB Power Change: ", USBpwr, PRIVATE); Log.info("USB ON"); } if (vADC <3 && USBpwr=="ON") { // Add event that USB power was lost USBpwr="OFF"; //Particle.publish("USB Power Change: ", USBpwr, PRIVATE); Log.info("Lost USB"); s_lostUSB = Time.timeStr(); } iADC = analogRead(V33_PIN); vADC = iADC * 3.28 / 4096; // set to 3.28 to give correct measured voltage V33 = String(vADC,2); // 2 decimal places //Log.info("V33 ADC: " + String(iADC)); // show ADC value Log.info("V3.3: " + V33); // calculated voltage Vlipo = String(fuel.getVCell(),2); // LiPo voltage from fuelgauge Log.info("VLipo: " + Vlipo); int v = fuel.getSoC(); // State of Charge from fuelgauge sSoc = String(v); Log.info("SoC: " + sSoc); //Log.info("Vcell: " + fuel.getVCell()); //uint16_t cvolt = power.getChargeVoltageValue(); //Log.info("Charge V: " + String(cvolt)); float dhtval = dht.getTempFarenheit(); // Check for valid readings from DHT if (dhtval!=NAN) { TempF = int(dhtval); Log.info("Temp: " + String(TempF)); } delay(250); dhtval = dht.getHumidity(); if (dhtval!=NAN) { Humid = int(dhtval); Log.info("Humid: " + String(Humid)); } } String ToUp (String str) { // Convert string c to upper case String cs; for (std::string::size_type i=0; i