#include #include #include "pfodWifiConfig.h" #include "pfodWifiConfig_WiFly.h" #include "pfodSecurity.h" //#define DEBUG // NOTE: when USB cable connected it takes about 10sec to start up, USB startup ?? /* ===== pfod Command for pfodPowerSwitch ==== pfodApp msg {.} --> {.<+3>pfodPowerSwitches`1000|A~<+4>Left Output is `0~~OFF\ON|B~<+4>Right Output is `0~~OFF\ON} */ // Using Serial1 and 9600 for send and receive // Serial1 D0 (RX) and D1 (TX) on Arduino Leonardo, Yun and SparkFun FioV3 boards and D19 (RX) and D18 (TX) on Arduino Due and Mega boards /* Code generated by pfodDesigner V1.2.781 * (c)2014-2015 Forward Computing and Control Pty. Ltd. * NSW Australia, www.forward.com.au * This generated code may be freely used for both private and commerical use */ // ====================== pfodSecurity parser; // create a parser to handle the pfod messages pfodWifiConfig_WiFly pfodWifiConfig; // WiFi config for WiFly // =============== start of pfodWifiConfigionV1 settings ============== // update this define with the password from your QR code // http://www.forward.com.au/pfod/pfodWifiConfig/pfodQRpsk.html #define pfodWifiConfigPASSWORD "plyWtEDk6uZ0yfmAEM5wMc" // the ssid is pfodWifiConfigV1 and the port is 23 -- set by pfodQRpsk program // note pfodSecurity uses 19 bytes of eeprom usually starting from 0 so // start the eeprom address from 20 for pfodWifiConfig int eepromAddress = 20; // pfodWifiConfig uses pfodWifiConfig.EndEEPROM locations // =============== end of pfodWifiConfigionV1 settings ============== int switch1eepromAddress = eepromAddress + pfodWifiConfig.EndEEPROM + 1; // is the switch on or off on power up int switch2eepromAddress = switch1eepromAddress + 1; // is the switch on or off on power up // give the board pins names, if you change the pin number here you will change the pin controlled int cmd_A_var; // name the variable for 'Left Output is ' int cmd_B_var; // name the variable for 'Right Output is ' // Digital Pin Numbers // lower pin no -> IN1 // higher pin no -> IN2 const int SW1_PIN = 2; // switch input 1 const int SW2_PIN = 3; // switch input 2 const int RELAY1_PIN = 4; // switch input 1 const int RELAY2_PIN = 5; // switch input 2 const int OPTO1_PIN = 6; // switch input 1 const int OPTO2_PIN = 7; // switch input 2 const int LED1_PIN = 8; // switch led 1 const int LED2_PIN = 9; // switch led 2 DebouncedSwitch sw1(SW1_PIN); // monitor a switch on input SW1_PIN DebouncedSwitch sw2(SW2_PIN); // monitor a switch on input SW2_PIN boolean power1_on = false; boolean power2_on = false; boolean relay1_on = false; boolean relay2_on = false; /** these timers keep the leds lit during the half cycle of power when the opto coupler is not being driven Actually could not see the any brightness difference between half cycle and full cycle, but.. */ unsigned long led_1_timer; unsigned long led_2_timer; boolean led_1_on = false; boolean led_2_on = false; const unsigned long POWER_CYCLE_LENGTH = (1000 / 50); // 1 cycle of 50Hz in mS works for 60Hz system also boolean configMode = false; // set to true if both bottons pressed on start up const unsigned long FLASH_LENGTH = 200; // 2.5 cycles per sec. one cycle = ON / OFF Stream *client = NULL; // the connection to WiFly &Serial1 in this case // the setup routine runs once when you press reset: void setup() { pinMode(LED1_PIN, OUTPUT); // initially low (OFF) pinMode(LED2_PIN, OUTPUT); // initially low (OFF) Serial1.begin(9600); // UART connection to WiFly board #ifdef DEBUG Serial.begin(9600); #endif configMode = false; // start in config mode for testing false; // check if both push buttons pressed on power up // check if both push buttons pressed on power up if ((digitalRead(SW1_PIN) == LOW) && (digitalRead(SW2_PIN) == LOW)) { // start in config mode configMode = true; } // if configMode flash for 10 sec // allow a little time to connect the serialMonitor before running the rest of the setup. // also introduces a delay on power cycles to make it infeasable to deny access by using up all the power cycles. int flashCount = 10; boolean leds_ON = false; if (configMode) { flashCount = 10 * 1000 / FLASH_LENGTH; } for (int i = flashCount; i > 0; i--) { delay(FLASH_LENGTH); #ifdef DEBUG Serial.print(F(" ")); Serial.print(i); #endif if (configMode) { leds_ON = !leds_ON; if (leds_ON) { digitalWrite(LED1_PIN, HIGH); digitalWrite(LED2_PIN, HIGH); } else { digitalWrite(LED2_PIN, LOW); digitalWrite(LED1_PIN, LOW); } } } #ifdef DEBUG Serial.println(); #endif pinMode(RELAY1_PIN, OUTPUT); // initially low (OFF) pinMode(RELAY2_PIN, OUTPUT); // initially low (OFF) pinMode(OPTO1_PIN, INPUT_PULLUP); pinMode(OPTO2_PIN, INPUT_PULLUP); client = &Serial1; //============ pfodWifiConfigV1 config ==================== // see if both buttons is pressed if (configMode) { #ifdef DEBUG Serial.println(F("Starting pfodWifiConfigV1")); #endif //pfodWifiConfig.setDebugStream(&Serial); // add this line is using DEBUG in pfodWifiConfig_LinkIt library code // connect to temporary wifi network for setup // the features determine the format of the {set...} command uint16_t ipSources = pfodFeatures::DHCP|pfodFeatures::STATIC_IP; // bit or these together pfodFeatures::DHCP|pfodFeatures::STATIC_IP if both are available uint16_t security = pfodFeatures::WPA2; // bit or these together e.g. pfodFeatures::OPEN | pfodFeatures::WPA pfodWifiConfig.configureWifiConfig(client,eepromAddress,"pfodWifiConfigV1",pfodWifiConfigPASSWORD,23, pfodFeatures::SERVER, security, ipSources ); // configureWifiConfig never returns. Need to reboot afterwards } //============ end pfodWifiConfigV1 config ==================== // else button was not pressed continue to load the stored network settings //else use configured setttings from EEPROM // use these local vars char ssid[pfodWifiConfig::MAX_SSID_LEN + 1]; // allow for null char password[pfodWifiConfig::MAX_PASSWORD_LEN + 1]; char staticIP[pfodWifiConfig::MAX_STATICIP_LEN + 1]; uint16_t portNo = 0; uint16_t security = 0; uint16_t ipSource = 0; byte mode = 0; pfodWifiConfig.loadNetworkConfigFromEEPROM(eepromAddress, &mode, (char*)ssid, pfodWifiConfig::MAX_SSID_LEN + 1, (char*)password, pfodWifiConfig::MAX_PASSWORD_LEN + 1, &security, &portNo, &ipSource, (char*)staticIP, pfodWifiConfig::MAX_STATICIP_LEN + 1); #ifdef DEBUG Serial.println(F("Connecting to AP")); Serial.print("ssid '"); Serial.print(ssid); Serial.println("'"); Serial.print("password '"); Serial.print(password); Serial.println("'"); #endif pfodWifiConfig.setupWiFi(client, ssid, password, staticIP, portNo); parser.setIdleTimeout(30); // set 30sec timeout to prevent attacker holding connection // pfodApp will re-request main menu every second so will not timeout. parser.connect(&Serial1,F(pfodWifiConfigPASSWORD),0); // connect the parser to the i/o stream with this password and user eeprom starting from 0 cmd_A_var = 0; cmd_B_var = 0; // set the relay state to same as when power was disconnected setRelay1State(EEPROM.read(switch1eepromAddress)); setRelay2State(EEPROM.read(switch2eepromAddress)); #ifdef DEBUG Serial.println("Finished setup"); #endif led_1_timer = millis(); led_2_timer = millis(); } // the loop routine runs over and over again forever: void loop() { byte cmd = parser.parse(); // pass it to the parser // parser returns non-zero when a pfod command is fully parsed if (cmd != 0) { // have parsed a complete msg { to } byte* pfodFirstArg = parser.getFirstArg(); // may point to \0 if no arguments in this msg. long pfodLongRtn; // used for parsing long return arguments, if any if ('.' == cmd) { // pfodApp has connected and sent {.} , it is asking for the main menu // send back the menu designed sendMainMenu(); // now handle commands returned from button/sliders } else if('A'==cmd) { // user moved slider -- 'Left Output is ' // in the main Menu of pfodPowerSwitch // set output based on slider 0 == LOW, 1 == HIGH parser.parseLong(pfodFirstArg,&pfodLongRtn); // parse first arg as a long cmd_A_var = (byte)pfodLongRtn; // set variable // ======= add this code // now set variable for relay and for menu update setRelay1State((byte)cmd_A_var); // ======= sendMainMenuUpdate(); // always send back a pfod msg otherwise pfodApp will disconnect. } else if('B'==cmd) { // user moved slider -- 'Right Output is ' // in the main Menu of pfodPowerSwitch // set output based on slider 0 == LOW, 1 == HIGH parser.parseLong(pfodFirstArg,&pfodLongRtn); // parse first arg as a long cmd_B_var = (int)pfodLongRtn; // set variable // ======= add this code // now set variable for relay and for menu update setRelay2State((byte)cmd_B_var); // ======= sendMainMenuUpdate(); // always send back a pfod msg otherwise pfodApp will disconnect. } else if ('!' == cmd) { // CloseConnection command closeConnection(parser.getPfodAppStream()); } else { // unknown command parser.print(F("{}")); // always send back a pfod msg otherwise pfodApp will disconnect. } } // <<<<<<<<<<< Your other loop() code goes here sw1.update(); // call this every loop to update switch state sw2.update(); // call this every loop to update switch state int opto1 = digitalRead(OPTO1_PIN); // check AC power int opto2 = digitalRead(OPTO2_PIN); // check AC power if (!opto1) { turnLed1On(); } if (!opto2) { turnLed2On(); } if ((led_1_on) && ((millis() - led_1_timer) > POWER_CYCLE_LENGTH)) { // have gone one power cycle and opto was not turned on so NO AC led_1_on = false; // turn led off } if ((led_2_on) && ((millis() - led_2_timer) > POWER_CYCLE_LENGTH)) { // have gone one power cycle and opto was not turned on so NO AC led_2_on = false; // turn led off } if (led_1_on) { digitalWrite(LED1_PIN, HIGH); } else { digitalWrite(LED1_PIN, LOW); } if (led_2_on) { digitalWrite(LED2_PIN, HIGH); } else { digitalWrite(LED2_PIN, LOW); } if (relay1_on) { digitalWrite(RELAY1_PIN, HIGH); } else { digitalWrite(RELAY1_PIN, LOW); } if (relay2_on) { digitalWrite(RELAY2_PIN, HIGH); } else { digitalWrite(RELAY2_PIN, LOW); } if (sw1.isChanged()) { // debounced switch changed state Up or Down // isChanged() is only true for one loop(), cleared when update() called again if (sw1.isDown()) { // switch was just pressed // toggle the led // read current value and set opposite one setRelay1State((byte)!relay1_on); } } if (sw2.isChanged()) { // debounced switch changed state Up or Down // isChanged() is only true for one loop(), cleared when update() called again if (sw2.isDown()) { // switch was just pressed // toggle the led // read current value and set opposite one setRelay2State((byte)!relay2_on); } } } // turn on led 1 and start timer void turnLed1On() { led_1_timer = millis(); // reset timer led_1_on = true; } // turn on led 2 and start timer void turnLed2On() { led_2_timer = millis(); // reset timer led_2_on = true; } /** * state == 0 for off else ON */ void setRelay1State(byte state) { if (((relay1_on) && (state!=0)) || ((!relay1_on) && (state==0))) { // no change } else { if (state) { relay1_on = true; turnLed1On(); } else { relay1_on = false; led_1_on = false; } // save state to EEPROM EEPROM.write(switch1eepromAddress,state); } } /** * state == 0 for off else ON */ void setRelay2State(byte state) { if (((relay2_on) && (state!=0)) || ((!relay2_on) && (state==0))) { // no change } else { if (state) { relay2_on = true; turnLed2On(); } else { relay2_on = false; led_2_on = false; } // save state to EEPROM EEPROM.write(switch2eepromAddress,state); } } void closeConnection(Stream *io) { // add any special code here to force connection to be dropped // code what ever is needed to force the link to disconnect // typically get into cmd mode and either reboot or close the link // for RN wifi Xbee module need to wait >250mS send $$$ and then wait >250mS // then send close and exit // should get EXIT back char EXIT[6] = {'E', 'X', 'I', 'T', 13, 10}; boolean foundExit = false; while (!foundExit) { delay(300); io->write('$'); io->write('$'); io->write('$'); delay(300); io->print("close\r"); delay(300); io->print("exit\r"); // wait for EXIT foundExit = io->find(EXIT, 6); }; } void sendMainMenu() { parser.print(F("{.")); // start a Menu screen pfod message send_menuContents(); // send the menu contents for pfodPowerSwitch parser.print(F("}")); // close pfod message } void sendMainMenuUpdate() { parser.print(F("{:")); // start an Update Menu pfod message send_menuContents(); // send the menu contents for pfodPowerSwitch parser.print(F("}")); // close pfod message } // modify this method if you need to update the menu to reflect state changes void send_menuContents() { // send menu prompt parser.print(F("<+3>pfodPowerSwitches")); parser.print(F("`1000")); // send menu items parser.print(F("|A~<+4>Left Output is\n`")); // parser.print(cmd_A_var); // output the current state 0 Low or 1 High // add this code if (led_1_on) { parser.print('1'); // on } else { parser.print('0'); // off } parser.print(F("~~OFF\\ON")); // Note the \\ inside the "'s to send \ parser.print(F("|B~<+4>Right Output is\n`")); //parser.print(cmd_B_var); // output the current state 0 Low or 1 High // add this code if (led_2_on) { parser.print('1'); // on } else { parser.print('0'); // off } parser.print(F("~~OFF\\ON")); // Note the \\ inside the "'s to send \ // ============ end of menu item =========== }