/* Wifi OnOff Sample for command to turn On and command to turn Off No response expected to the command. Load this sketch to the Adafruit Feather ESP8266 module (Other ESP8266 modules can also be used) This code uses Arduino ESP8266 is V2.3.0. Other versions may not work as expected This code drives ledPin to indicate when connected Steady led == OK Fast Flash == Connection or msg problem. Slow Flash == Battery Low, connect USB supply to recharge. */ /** Wifi_OnOff https://www.forward.com.au/pfod/HomeAutomation/Wifi_OnOff/index.html (c)2017 Forward Computing and Control Pty. Ltd. This code may be freely used for both private and commerical use. Provide this copyright is maintained. */ /************************************************************************* Outline of code setup() Read battery volts. Do it here to get consistent reading before Wifi starts up. Turn on power pin to hold FET power switch on Check pushbuttons, On pushbutton take precidence. If none pressed then CHARGING, start irregular flash and return from setup Start power Off timer, 15sec to power Off Set indicator Led ON solid Connect to Network, if no connection after 6 sec fast flash Led and power of in 15sec. Connect to host/port for control. If cannot connection after 6 sec fast flash Led and power of in 15sec If loose connection later, and not already flashing an error, start fast flash and power off as normal Check battery level. If <3.65V slow flash until power off, in 15sec, but otherwise continue loop() If CHARGING check for user pressing a pushbutton and if so turn off FET power switch. else if power off timeout call powerOff, (close connection wait 1sec, turn flasher off, turn led off, make power pin low to drop supply. return if turn On/Off sequence and not flashing then finished call powerOff. else if CONNECTION_ERROR from processMsg start fast flash and reset power off timer for 15sec else if lost connection start fast flash and reset power off timer for 15sec else call processMsgs to send on/off command and check return if any */ #include #include #include #include char ssid[] = "*** ***"; char password[] = "********"; char staticIP[] = "10.1.1.180"; int portNo = 4989; const int ledPin = 15; // this has 4k7 resistor to GND on Feather ESP8266 board const int pushButton1pin = 14; // ON pushbutton, input with pullup enabled const int pushButton2pin = 13; // OFF pushbutton, input with pullup enabled const int powerControlPin = 12; // output high to keep power on enum flashTypeEnum {NO_FLASH, SLOW_FLASH, FAST_FLASH, CHARGING_FLASH}; volatile flashTypeEnum flashType = NO_FLASH; const float FLASH_TIMER_INTERVAL = 0.1; // 0.1 sec const int FAST_FLASH_PERIOD = 2; // 0.2sec const int FAST_FLASH_OFF = 1; // 50% flash const int SLOW_FLASH_PERIOD = 18; // 1.8sec const int SLOW_FLASH_OFF = 9; // 50% flash volatile int flashCounter = 0; volatile int flashOff = 1; volatile int flashPeriod = 1; // 3.35V == 698 to 704 ==> 3.65 == 761 to 767 counts // 4.19V == 879 to 881 ==> 3.65 == 766 to 767 count const int batteryLowVolts = 763; // 3.65V; int batteryVolts = 0; const size_t MAX_RETURN_MSG_LEN = 255; char returnMsg[MAX_RETURN_MSG_LEN + 1]; uint8_t parseReturn(uint8_t c); void parseReturnInit(); int checkLightState(); // comment out next line to diable DEBUG messages. NOTE: will ALWAYS get ESP8266 boot messages regardless #define DEBUG WiFiClient client; // just one client reused Ticker ledFlasher; bool ledOn = false; int pushButton = -1; // none 0 off, 1 on unsigned long powerOffTimer = 0; const unsigned long POWER_TIMEOUT = 15000; // 15sec turn power off regardless, unless charging enum msgStateEnum {CONNECTED, SENT_INQUIRY, SENT_ON_OFF, CONNECTION_FINISHED, CONNECTION_ERROR, CHARGING}; msgStateEnum msgState = CONNECTED; // processMsgs not called unless connected char *TURN_LIGHT_ON = "1"; // edit this string to the one that turns the device ON char *TURN_LIGHT_OFF = "0"; // edit this string to the one the turns the device OFF void processMsgs() { uint8_t cmd = 0; if ((msgState == CONNECTION_ERROR) || (msgState == CONNECTION_FINISHED)) { return; } else if (msgState == CONNECTED) { // send ON or OFF string depending on push button // else have light state now switch if (pushButton == 1) { // turn on client.print(TURN_LIGHT_ON); } else if (pushButton == 0) { // turn off client.print(TURN_LIGHT_OFF); } msgState = CONNECTION_FINISHED; // not need to send msg } // else ignore } void handleFlash() { if (flashType == NO_FLASH) { turnLedOn(); // just turn led on } else if (flashType == CHARGING_FLASH) { flashCounter++; if (flashCounter >= 24) { flashCounter = 0; // reset turnLedOn(); // OFF ON OFF 0N OFF 0N OFF } else if ((flashCounter == 4) || (flashCounter == 6) || (flashCounter == 14) || (flashCounter == 15) || (flashCounter == 16) || (flashCounter == 17) || (flashCounter == 18)) { toggleLed(); } } else { // flash flashCounter++; if (flashCounter >= flashPeriod) { flashCounter = 0; // reset turnLedOn(); } else if (flashCounter == flashOff) { toggleLed(); } } } void turnLedOn() { ledOn = true; digitalWrite(ledPin, HIGH); } void toggleLed() { ledOn = !ledOn; if (ledOn) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); } } void flashInit() { pinMode(ledPin, OUTPUT); turnLedOn(); // ON setFlash(NO_FLASH); ledFlasher.attach(FLASH_TIMER_INTERVAL, handleFlash); } /** Set flash type */ void setFlash(flashTypeEnum f_type) { if (f_type == NO_FLASH) { flashType = f_type; turnLedOn(); return; } if (f_type == flashType) { return; // no chabnge } if (f_type == CHARGING_FLASH) { flashType = f_type; turnLedOn(); flashCounter = 0; } else if (f_type > flashType) { turnLedOn(); flashCounter = 0; //up the flash speed, the above test ensures the powerOffTimer only reset once on switching to Fast Flash flashType = f_type; switch (flashType) { case FAST_FLASH: powerOffTimer = millis(); // reset power off time so will flash for full 15sec if error flashPeriod = FAST_FLASH_PERIOD; flashOff = FAST_FLASH_OFF; break; case SLOW_FLASH: flashPeriod = SLOW_FLASH_PERIOD; flashOff = SLOW_FLASH_OFF; break; default: break; } } } // pushbutton 1 (pin 14) is ON pushbutton // pushbutton 2 (pin 13) is OFF pushbutton int checkPushButtons() { // set pullups on inputs pinMode(pushButton1pin, INPUT_PULLUP); pinMode(pushButton2pin, INPUT_PULLUP); if (digitalRead(pushButton1pin) == LOW) { return 1; } if (digitalRead(pushButton2pin) == LOW) { return 0; } // else no pushbutton pushed start charging return -1; } void initVars() { ledOn = false; flashInit(); //pushButton = -1; // don't reset this msgState = CONNECTED; } void setup ( void ) { batteryVolts = analogRead(A0); // == do these first ================= pinMode(powerControlPin, OUTPUT); digitalWrite(powerControlPin, HIGH); // turn power on ON pushButton = checkPushButtons(); // -1 none pushed, 0 OFF, 1 ON pushbutton // ================================== powerOffTimer = millis(); // start power off timer initVars(); // keep this short, turns led on solid #ifdef DEBUG Serial.begin(74880); // for debug will output reboot chars (at 74880 baud) even if DEBUG not defined #endif delay(10); // Don't add any more delays here as the ESP8266 V2.3.0 library Wifi setup does not like it #ifdef DEBUG Serial.print("ADC:"); Serial.println(batteryVolts); #endif if (pushButton < 0) { // just charging msgState = CHARGING; setFlash(CHARGING_FLASH); #ifdef DEBUG Serial.println("CHARGING"); #endif return; } #ifdef DEBUG Serial.println(); Serial.println(F("Starting Setup")); #endif int countC = 0; WiFi.begin(ssid, password); while ((WiFi.status() != WL_CONNECTED) && (countC < 12)) { // max 6 sec. delay(500); #ifdef DEBUG Serial.print("."); #endif countC++; } if (WiFi.status() != WL_CONNECTED) { #ifdef DEBUG Serial.println(); Serial.println(F("Could not connect to Network!")); #endif return; } #ifdef DEBUG Serial.println(); Serial.println(F("Connected to Network!")); #endif setFlash(NO_FLASH); IPAddress hostip(pfodESP8266Utils::ipStrToNum(staticIP)); countC = 0; while ((client.status() != ESTABLISHED) && (countC < 12)) { // max 6 sec to connect client.connect(staticIP, portNo); // note this can return true when connection not complete, will return false later after first write. delay(500); #ifdef DEBUG Serial.print("+"); #endif countC++; } if (client.status() != ESTABLISHED) { #ifdef DEBUG Serial.print("connection failed to "); Serial.print(staticIP); Serial.print(":"); Serial.println(portNo); #endif return; } setFlash(NO_FLASH); // check for battery low here and turn on flasher if (batteryVolts <= batteryLowVolts) { #ifdef DEBUG Serial.print("Battery Low "); Serial.println(batteryVolts); #endif setFlash(SLOW_FLASH); } } void loop() { if (msgState == CHARGING) { // check for button pressed to stop charging int buttonPressed = checkPushButtons(); if ((buttonPressed >= 0) && (pushButton < 0)) { // if user pressed any pushbutton while charging latch it pushButton = buttonPressed; } if (pushButton >= 0) { // user presses any push button while charging // stop and turn off powerOff(); } // NOTE: power will stay on until user releases pushbutton and then turn off in <1sec } else { // NOT CHARGING if ((millis() - powerOffTimer) > POWER_TIMEOUT) { powerOff(); return; } // else not power timed out if (msgState == CONNECTION_FINISHED) { // finished if (flashType == NO_FLASH) { // no error flashing powerOff(); // turn off now } } else if (msgState == CONNECTION_ERROR) { if (flashType != FAST_FLASH) { #ifdef DEBUG Serial.println("msgState == CONNECTION_ERROR"); #endif } setFlash(FAST_FLASH); } else if (!client.connected()) { if (flashType != FAST_FLASH) { #ifdef DEBUG Serial.println("Not connected or CONNECTION_ERROR"); #endif } setFlash(FAST_FLASH); } else { processMsgs(); } } } bool poweredOff = false; void powerOff() { client.stop(); delay(500); // give tcp time to close if (!poweredOff) { #ifdef DEBUG Serial.print("power off after "); Serial.print( (float)(millis() - powerOffTimer) / 1000.0); Serial.println(" sec."); #endif } poweredOff = true; ledFlasher.detach(); digitalWrite(ledPin, LOW); // OFF // // and TURN OFF POWER PIN !! digitalWrite(powerControlPin, LOW); // ON }