Added files via upload

This commit is contained in:
nikant 2016-04-02 00:16:51 +03:00
parent f58bbe1b79
commit a9e7fb6cb9
5 changed files with 1340 additions and 0 deletions

25
NKNTP.h Normal file
View File

@ -0,0 +1,25 @@
// The Timezone library is modified by nikant to remove eeprom access
// commented out sections:
// file: Timezone.cpp
// line 12 #include eeprom
// line 28-31, whole of Timezone::Timezone function
// line 184-189, whole of Timezone::readRules function
// line 196-201, whole of Timezone::writeRules function
// file: Timezone.h
// lines: 42, 48, 49
// You can edit NKNTP.h in order to change to your Timezone and DST
// check https://github.com/JChristensen/Timezone/blob/master/ReadMe.md for examples.
#include <Timezone.h> //https://github.com/JChristensen/Timezone
//Eastern European Time Zone
// http://www.epochconverter.com/timezones
extern TimeChangeRule myDST = {"EEST", Last, Sun, Mar, 3, 180}; //Daylight time = UTC + 3 hours
extern TimeChangeRule mySTD = {"EET", Last, Sun, Nov, 4, 120}; //Standard time = UTC + 2 hours
extern Timezone myTZ(myDST, mySTD);
extern boolean NTPsuccess;
void NTP2localTime();
void getTheNTPTime();

141
NKNTP.ino Normal file
View File

@ -0,0 +1,141 @@
/*
"Get time (epoch) and local time through an NTP server"
modified from https://github.com/sandeepmistry/esp8266-Arduino/blob/master/esp8266com/esp8266/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
----------------
You can edit NKNTP.h in order to change to your Timezone and DST
check https://github.com/JChristensen/Timezone/blob/master/ReadMe.md for examples.
--------------------------------------------------------------------------------
*/
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// the Timezone library is modified by nikant to remove eeprom access, check Timezone.h and Timezone.cpp for commented out sections
#include <Timezone.h> //https://github.com/JChristensen/Timezone
unsigned int localPort = 2390; // local port to listen for UDP packets
/* Don't hardwire the IP address or we won't get the benefits of the pool.
* Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
boolean NTPsuccess = false;
void getTheNTPTime() {
Serial.println(F("Starting UDP"));
udp.begin(localPort);
Serial.print(F("Local port: "));
Serial.println(udp.localPort());
//get a random server from the pool
WiFi.hostByName(ntpServerName, timeServerIP);
sendNTPpacket(timeServerIP); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);
int cb = udp.parsePacket();
if (!cb) {
Serial.println(F("no packet yet"));
}
else {
Serial.print(F("packet received, length="));
Serial.println(cb);
// We've received a packet, read the data from it
udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
//Serial.print("Seconds since Jan 1 1900 = " );
//Serial.println(secsSince1900);
// now convert NTP time into everyday time:
Serial.print(F("Unix time = "));
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
Serial.println(epoch);
// set time to local timezone
setTime(myTZ.toLocal(epoch));
NTPsuccess = true;
}
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
{
Serial.println(F("sending NTP packet..."));
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
}
void NTP2localTime() {
int gettimestamp = 0;
getTheNTPTime();
while (year() == 1970) {
delay(1000);
getTheNTPTime();
gettimestamp += 1;
if (gettimestamp == 5) {
NTPsuccess = false;
break;
}
}
gettimestamp = 0;
}

818
THE433.ino Normal file
View File

@ -0,0 +1,818 @@
/*
"THE433"
"control 433MHz (compatible with Arduino libs) sockets/devices through web and time rules"
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- thanks goes to fivosv for his patience to help me
----------------
https://github.com/nikant/THE433/blob/master/README.md
used Arduino IDE: 1.6.5-r5
Files:
- THE433.ino // main sketch
- NKTP.h & NKNTP.ino // get NTP time and convert to local time. Needs modified Timezone library, check NKNTP.h
- espWiFi2eeprom.h & espWiFi2eeprom.ino // esp8266 WiFi configuration to eeprom manager for Arduino IDE, check espWiFi2eeprom.h
Libraries needed:
- ESP/Arduino core (used working version 2.1.0)
- RCSwitch library for 433MHz RF control // https://github.com/sui77/rc-switch/
- (not a library) espWiFi2eeprom // https://github.com/nikant/espWiFi2eeprom
- Time library // https://github.com/PaulStoffregen/Time
- TimeAlarms library modified dtNBR_ALARMS from 6 to 11 // https://github.com/PaulStoffregen/TimeAlarms
- TimeZone library modified by nikant to remove eeprom access, check NKNTP.h // https://github.com/JChristensen/Timezone
----------------
To use this you have to know how to work with RF 433MHz switches/sockets and have
the needed transmitters/receivers for your esp8266 or NodeMCU dev kit.
In order to connect to WiFi this uses the espWiFi2eeprom added files.
You can read an example of how they work here: https://github.com/nikant/espWiFi2eeprom
and see some screenshots here: https://nobugsjustfeatures.wordpress.com/2016/03/27/esp8266-yet-another-esp-wifi-config-to-eeprom/
You must also set your own time zone in the NKNTP.h file.
Remember to set the appropriate 433 MHz RCSwitch codes to the "433 functions" section add new functions if needed
and their names to the TcommandsFunctions array.
Also the equal number of names to the TcommandsFNames array. Those last strings are also used from the main form of the web interface
to command an RF switch.
--------------------------------------------------------------------------------
*/
#include "FS.h" // https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiClient.h>
#include <RCSwitch.h>
#include "espWiFi2eeprom.h" // https://github.com/nikant/espWiFi2eeprom
#include "NKNTP.h"
#include <Time.h>
#include <TimeAlarms.h> // https://www.pjrc.com/teensy/td_libs_TimeAlarms.html
#define THE433_VERSION "0.5"
// Initialize the 433MHz RF switch
RCSwitch mySwitch = RCSwitch();
// Update these with values suitable for your network.
IPAddress nkip(192, 168, 1, 101); //Node static IP
IPAddress nkgateway(192, 168, 1, 1);
IPAddress nksubnet(255, 255, 255, 0);
// Port of esp8266 webserver
ESP8266WebServer server(80);
// 433MHz RF pins for esp8266 and the onboard led
// pin 4 is GPIO4 which is D2 in the NodeMCU v1.0 board.
const int RCSwitchPin = 4;
const int ONBOARDLED = 2;
// Filename of SPIFFS savefile with TimeCommands
// ! Always with a / at the beginning of the filename !
#define TCSaveFile "/TCconfig.ini"
// Delimiter used in TimeCommands savefile: 1 character
#define TCSaveFileDelimiter ","
// Keyword to enter the Time Commands center from the start page
#define TCOMMANDWORD "ENTERTIMECOMMANDS"
// Available commands for all the 433MHz devices to be controled
// All functions available at the "433 functions" section below
// Function names
void (*TCommandsFunctions[])() = {switchon1, switchoff1, switchon2, switchoff2};
// Keywords that fire the 433MHz functions from the start page
char* TCommandsFNames[] = {"SWITCH 1 ON", "SWITCH 1 OFF", "SWITCH 2 ON", "SWITCH 2 OFF"};
// Calculate number of functions
#define numAvailFuncs (sizeof(TCommandsFNames)/sizeof(char *))
// The number of alarms can be changed in the TimeAlarms header file TimeAlarms.h set by the constant dtNBR_ALARMS
// note that the RAM used equals dtNBR_ALARMS * 11 bytes
// right now for THE433 project it is set to #define dtNBR_ALARMS 11
// for 10 Alarms possible + 1 for the cleanup function
#define MAXTCommands dtNBR_ALARMS - 1
// Array that holds the Time Commands that are executed Once in RAM so they can be deleted from SPIFFS save file in the future
String alarmepochs[MAXTCommands][2];
int countTCommands;
// -------------------------------- START WEB and MESSAGES ---------------------------------
// HTML Strings etc.
String TCsubmitResult = "";
String SPIFFSstatus;
String SPIFFSTCommandsList;
String pinstate = "<h2>-</h2>";
const char webPageClearTCButton[] PROGMEM = "<br><form action=\"/removeTCSaveFile\" target=\"_top\"><input type=\"submit\" value=\"! Delete TimeCommands file !\"></form>\n";
const char webPageHomeButton[] PROGMEM = "<br><form action=\"/\" target=\"_top\"><input type=\"submit\" value=\"home\"></form>\n";
const char webPage433form[] PROGMEM = "\n<form action='/submit' method='POST'><input type=\"text\" name=\"pin\" value=\"\"><br><input type=\"submit\" value=\"Submit\"></form>\n";
const char webPageTC_0[] PROGMEM = "<table style=\"margin-left: auto;margin-right: auto;width:80%;border: 1px solid #fff;\"><tr>"
"<td style=\"text-align:center;width:10%;\">&nbsp;</td><td style=\"text-align:left;width:40%;\"><br>";
const char webPageTC_1[] PROGMEM = "<br><br><form action='/TCsubmit' method='POST'><b>Time Command:</b>&nbsp;<input type=\"text\" name=\"tmcommand\" id=\"formtmcommand\" value=\"\" required=\"required\"><br><br><br><b>Schedule:</b>&nbsp;<br><br>"
"<input type=\"radio\" name=\"AlarmType\" value=\"AlarmOnce\">&nbsp;<b>Alarm Once</b><br>(once when the time next reaches the given hour, minute)<br><br><input type=\"radio\" name=\"AlarmType\" value=\"AlarmRepeatDaily\">&nbsp;<b>Daily Alarm Repeat</b><br>(every day at the given hour, minute)<br><br>"
"<input type=\"radio\" name=\"AlarmType\" value=\"AlarmOnceDOW\">&nbsp;<b>Weekly Alarm Once</b><br>(once only on the next DayOfWeek, hour, minute)<br><br><input type=\"radio\" name=\"AlarmType\" value=\"AlarmRepeatDOW\">&nbsp;<b>Weekly Alarm Repeat</b><br>(every week on the given DayOfWeek, hour, minute)<br><br><br><br><b>Time:</b>&nbsp;<br><br>"
"Day:&nbsp;<select size=\"1\" name=\"tcdow\" required=\"required\" id=\"formtcdow\">"
"<option value=\"\">&nbsp;</option><option value=\"nodow\" selected>none</option><option value=\"1\">Sunday</option><option value=\"2\">Monday</option><option value=\"3\">Tuesday</option><option value=\"4\">Wednesday</option><option value=\"5\">Thursday</option><option value=\"6\">Friday</option><option value=\"7\">Saturday</option>"
"</select>&nbsp;&nbsp;Hour:&nbsp;<select size=\"1\" name=\"tchour\" required=\"required\" id=\"formtchour\">"
"<option value=\"\">&nbsp;</option><option value=\"0\" selected>00</option><option value=\"1\">1</option><option value=\"2\">2</option><option value=\"3\">3</option><option value=\"4\">4</option><option value=\"5\">5</option><option value=\"6\">6</option><option value=\"7\">7</option><option value=\"8\">8</option><option value=\"9\">9</option>"
"<option value=\"10\">10</option><option value=\"11\">11</option><option value=\"12\">12</option><option value=\"13\">13</option><option value=\"14\">14</option><option value=\"15\">15</option><option value=\"16\">16</option><option value=\"17\">17</option><option value=\"18\">18</option><option value=\"19\">19</option><option value=\"20\">20</option><option value=\"21\">21</option><option value=\"22\">22</option><option value=\"23\">23</option>"
"</select>&nbsp;&nbsp;Minutes:&nbsp;<select size=\"1\" name=\"tcminutes\" required=\"required\" id=\"formtcminutes\">"
"<option value=\"\">&nbsp;</option><option value=\"0\" selected>00</option><option value=\"1\">1</option><option value=\"2\">2</option><option value=\"3\">3</option><option value=\"4\">4</option><option value=\"5\">5</option><option value=\"6\">6</option><option value=\"7\">7</option><option value=\"8\">8</option><option value=\"9\">9</option>"
"<option value=\"10\">10</option><option value=\"11\">11</option><option value=\"12\">12</option><option value=\"13\">13</option><option value=\"14\">14</option><option value=\"15\">15</option><option value=\"16\">16</option><option value=\"17\">17</option><option value=\"18\">18</option><option value=\"19\">19</option><option value=\"20\">20</option><option value=\"21\">21</option><option value=\"22\">22</option><option value=\"23\">23</option>"
"<option value=\"24\">24</option><option value=\"25\">25</option><option value=\"26\">26</option><option value=\"27\">27</option><option value=\"28\">28</option><option value=\"29\">29</option><option value=\"30\">30</option><option value=\"31\">31</option><option value=\"32\">32</option><option value=\"33\">33</option><option value=\"34\">34</option><option value=\"35\">35</option><option value=\"36\">36</option><option value=\"37\">37</option>"
"<option value=\"38\">38</option><option value=\"39\">39</option><option value=\"40\">40</option><option value=\"41\">41</option><option value=\"42\">42</option><option value=\"43\">43</option><option value=\"44\">44</option><option value=\"45\">45</option><option value=\"46\">46</option><option value=\"47\">47</option>"
"<option value=\"48\">48</option><option value=\"49\">49</option><option value=\"50\">50</option><option value=\"51\">51</option><option value=\"52\">52</option><option value=\"53\">53</option><option value=\"54\">54</option><option value=\"55\">55</option><option value=\"56\">56</option><option value=\"57\">57</option><option value=\"58\">58</option><option value=\"59\">59</option>"
"</select>&nbsp;&nbsp;<br><br><input type=\"submit\" value=\"Submit\"></form><br>"
"</td><td style=\"text-align:center;width:10%;\">&nbsp;</td><td style=\"text-align:left;width:40%;\"><br><br>";
const char webPageTC_2[] PROGMEM = "<br><br></td></tr></table>\n";
const char NTPfail[] PROGMEM = "<br><br><p style=\"font-size:medium\"><b>NTP Time failure. TimeCommands are not available!</b></p>\n";
const char SPIFFSTCommandsList_1[] PROGMEM = "<hr><br><b>---&nbsp;TimeCommands in SPIFFS&nbsp;---</b>";
const char SPIFFSTCommandsList_2[] PROGMEM = "<br><b>---&nbsp;-&nbsp;---</b><br><br>";
const char SPIFFSTCommandsList_3[] PROGMEM = "<form action=\"/TClistdelline\" target=\"_top\"><ul style=\"list-style-type:none\">";
const char SPIFFSTCommandsList_4[] PROGMEM = "<li><input type=\"radio\" name=\"TC2Remove\" value=\"";
const char SPIFFSTCommandsList_5[] PROGMEM = "</ul><input type=\"submit\" value=\"delete selected TimeCommand\"></form>\n";
const char esprestartmsg[] PROGMEM = "<br>Restart esp in order to activate TimeCommands!";
const char webPageRestartButton[] PROGMEM = "<br><form action=\"/esp433restart\" target=\"_top\"><input type=\"submit\" value=\"! RESTART ESP !\"></form>\n";
String webPageFooter = "\n<br>- version: " THE433_VERSION " -\n<br>ESP Free Heap: " + String(ESP.getFreeHeap()) + "\n</body></html>";
String webPageHeader(String webtitle, String webpagetitle, String backcolor, String fontcolor) {
return "<!DOCTYPE HTML>\n"
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><title>" + webtitle + "</title>\n"
"<style type=\"text/css\">body {text-align:center;font-family: sans-serif;background-color: " + backcolor + ";color: " + fontcolor + ";} a:link, a:visited, a:hover, a:active {color:" + fontcolor + ";}</style>\n"
"</head>\n"
"<body>\n"
"<h1>" + webpagetitle + "</h1>\n";
}
// Lists the available Time Commands for the web interface
String TCommandsCall() {
String TCwebstring = "<ul style=\"list-style-type:none\">";
for (int i = 0; i < numAvailFuncs; ++i) {
String thetcommand = TCommandsFNames[i];
TCwebstring += "<li>";
TCwebstring += i + 1;
TCwebstring += ":&nbsp;&nbsp;<b>";
TCwebstring += "<a href=\"#\" target=\"_top\" onClick=\"document.getElementById(\'formtmcommand\').value=\'" + thetcommand + "\'\">";
TCwebstring += thetcommand;
TCwebstring += "</a>";
TCwebstring += "</b>&nbsp;&nbsp;<br><br>";
TCwebstring += "</li>";
}
TCwebstring += "</ul>";
return TCwebstring;
}
// -------------------------------- END WEB ---------------------------------
// -------------------------------- START 433 functions ---------------------------------
// Main 433MHz RF functions. Can be called from main page of the web interface with the keyowrds at the top.
void switchon1() {
digitalWrite(ONBOARDLED, LOW);
for (int i = 0; i <= 19; i++) {
mySwitch.setPulseLength(260); // this should be set according to your reading from RF receiver
mySwitch.send("010101010101010101010101"); // sample raw data for 433MHz RF transmitter
Serial.print("1 ON ");
Serial.println(i);
delay(100);
}
pinstate = F("<h2>1</h2>");
digitalWrite(ONBOARDLED, HIGH);
}
void switchoff1() {
digitalWrite(ONBOARDLED, LOW);
for (int i = 0; i <= 19; i++) {
mySwitch.setPulseLength(260); // this should be set according to your reading from RF receiver
mySwitch.send("010101010101010101010101"); // sample raw data for 433MHz RF transmitter
Serial.print("1 OFF ");
Serial.println(i);
delay(100);
}
pinstate = F("<h2>0</h2>");
digitalWrite(ONBOARDLED, HIGH);
}
void switchon2() {
digitalWrite(ONBOARDLED, LOW);
for (int i = 0; i <= 19; i++) {
mySwitch.setPulseLength(260); // this should be set according to your reading from RF receiver
mySwitch.send("010101010101010101010101"); // sample raw data for 433MHz RF transmitter
Serial.print("2 ON ");
Serial.println(i);
delay(100);
}
pinstate = F("<h2>1</h2>");
digitalWrite(ONBOARDLED, HIGH);
}
void switchoff2() {
digitalWrite(ONBOARDLED, LOW);
for (int i = 0; i <= 19; i++) {
mySwitch.setPulseLength(260); // this should be set according to your reading from RF receiver
mySwitch.send("010101010101010101010101"); // sample raw data for 433MHz RF transmitter
Serial.print("2 OFF ");
Serial.println(i);
delay(100);
}
pinstate = F("<h2>0</h2>");
digitalWrite(ONBOARDLED, HIGH);
}
// -------------------------------- END 433 functions ---------------------------------
// -------------------------------- START general functions ---------------------------------
// Pad time digits with zeros for HTML
String calcDigits(int digits) {
// utility function for digital clock display: prints preceding colon and leading 0
String stringDigi = "";
if (digits < 10) stringDigi = "0" + String(digits);
else stringDigi = String(digits);
return stringDigi;
}
// Time.h (library) function to convert given time to seconds
time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
{
tmElements_t tmSet;
tmSet.Year = YYYY - 1970;
tmSet.Month = MM;
tmSet.Day = DD;
tmSet.Hour = hh;
tmSet.Minute = mm;
tmSet.Second = ss;
return makeTime(tmSet); //convert to time_t
}
// -------------------------------- END general functions ---------------------------------
// -------------------------------- START ALARM functions ---------------------------------
// Empty array of Time Commands at boot
void nullFillalarmepochs() {
for (int i = 0; i < MAXTCommands; i++)
for (int j = 0; j < 2; j++) {
alarmepochs[i][j] = "";
}
}
// Function to delete Time Commands that have been executed and where set to execute Once only from SPIFFS save file
void CleanupTC() {
//debug
//Serial.print("tic "); Serial.println(second());
for (int i = 0; i < MAXTCommands; i++) {
if ((alarmepochs[i][0] != "") && (alarmepochs[i][1] != "")) {
unsigned long chcktm = alarmepochs[i][0].toInt();
if (chcktm > 0) {
// No need to set it here. It is set at main setup function at the end.
//chcktm = chcktm + (2 * 60); // (minutes * seconds) that must have passed in order to clean the alarm event
if (now() > chcktm) {
RemoveLinesSpiffsTC(alarmepochs[i][1]);
delay(100);
for (int j = 0; j < 2; j++) {
alarmepochs[i][j] = "";
}
Serial.println(F("periodic cleanup: TimeCommand removed!"));
}
}
}
}
}
// Add Time Commands that are set to execute Once only to an array to be cleaned from SPIFFS save file
void SetupCleanTimer(String inTC, String OnceTCepoch, int inLine) {
inTC.replace("\n", "");
inTC.trim();
alarmepochs[inLine - 1][0] = OnceTCepoch;
alarmepochs[inLine - 1][1] = inTC;
}
// Set Time Commands to Alarms from TimeAlarms library at boot
void SetupAlarms(int tmpTCommand, String tmpAlarmType, String tmpDOW, int tmpTChour, int tmpTCminute) {
if (tmpAlarmType == "AlarmRepeatDaily") {
Alarm.alarmRepeat(tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
Serial.println(F("Alarm set!"));
} else if (tmpAlarmType == "AlarmOnce") {
Alarm.alarmOnce(tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
Serial.println(F("Alarm set!"));
} else {
//dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, or dowSaturday
if (tmpAlarmType == "AlarmRepeatDOW") {
if (tmpDOW == "1") {
Alarm.alarmRepeat(dowSunday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "2") {
Alarm.alarmRepeat(dowMonday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "3") {
Alarm.alarmRepeat(dowTuesday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "4") {
Alarm.alarmRepeat(dowWednesday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "5") {
Alarm.alarmRepeat(dowThursday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "6") {
Alarm.alarmRepeat(dowFriday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "7") {
Alarm.alarmRepeat(dowSaturday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
}
Serial.println(F("Alarm set!"));
} else if (tmpAlarmType == "AlarmOnceDOW") {
if (tmpDOW == "1") {
Alarm.alarmOnce(dowSunday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "2") {
Alarm.alarmOnce(dowMonday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "3") {
Alarm.alarmOnce(dowTuesday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "4") {
Alarm.alarmOnce(dowWednesday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "5") {
Alarm.alarmOnce(dowThursday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "6") {
Alarm.alarmOnce(dowFriday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
} else if (tmpDOW == "7") {
Alarm.alarmOnce(dowSaturday, tmpTChour, tmpTCminute, 0, TCommandsFunctions[tmpTCommand]);
}
Serial.println(F("Alarm set!"));
}
}
// Alarm.delay to feed the TimeAlarms library
Alarm.delay(100);
}
// Parse lines from the SPIFFS save file into SetupAlarms function above
// and also to the commands to be cleaned array
void parseTC(String inTC, int inLine) {
int tmpTCommand, tmpTChour, tmpTCminute, ind1, ind2, ind3, ind4, ind5, ind6;
String tmpAlarmType, TCcc, TChh, TCmm, tmpDOW, tmpOnceTCepoch, tmpisOnce;
ind1 = inTC.indexOf(TCSaveFileDelimiter);
ind2 = inTC.indexOf(TCSaveFileDelimiter, ind1 + 1);
ind3 = inTC.indexOf(TCSaveFileDelimiter, ind2 + 1);
ind4 = inTC.indexOf(TCSaveFileDelimiter, ind3 + 1);
ind5 = inTC.indexOf(TCSaveFileDelimiter, ind4 + 1);
ind6 = inTC.indexOf(TCSaveFileDelimiter, ind5 + 1);
TCcc = inTC.substring(0, ind1);
tmpTCommand = TCcc.toInt();
tmpAlarmType = inTC.substring(ind1 + 1, ind2);
tmpDOW = inTC.substring(ind2 + 1, ind3);
TChh = inTC.substring(ind3 + 1, ind4);
tmpTChour = TChh.toInt();
TCmm = inTC.substring(ind4 + 1, ind5);
tmpTCminute = TCmm.toInt();
tmpOnceTCepoch = inTC.substring(ind5 + 1, ind6);
tmpisOnce = inTC.substring(ind6 + 1);
SetupAlarms(tmpTCommand, tmpAlarmType, tmpDOW, tmpTChour, tmpTCminute);
// set commands that are Once only to an array to be cleaned from SPIFFS save file
if (tmpisOnce == "1") SetupCleanTimer(inTC, tmpOnceTCepoch, inLine);
//Serial.println(inLine); Serial.println(tmpOnceTCepoch);
}
// Parse lines from the SPIFFS save file for HTML show
String parseTC2HTML(String inTC, int inLine) {
String tmpAlarmType, TCcc, tmpTChour, tmpTCminute, TCdd, parsed2html;
int ind1, ind2, ind3, ind4, ind5, ind6, tmpTCommand, tmpDOW;
ind1 = inTC.indexOf(TCSaveFileDelimiter);
ind2 = inTC.indexOf(TCSaveFileDelimiter, ind1 + 1);
ind3 = inTC.indexOf(TCSaveFileDelimiter, ind2 + 1);
ind4 = inTC.indexOf(TCSaveFileDelimiter, ind3 + 1);
ind5 = inTC.indexOf(TCSaveFileDelimiter, ind4 + 1);
ind6 = inTC.indexOf(TCSaveFileDelimiter, ind5 + 1);
TCcc = inTC.substring(0, ind1);
tmpTCommand = TCcc.toInt();
tmpAlarmType = inTC.substring(ind1 + 1, ind2);
TCdd = inTC.substring(ind2 + 1, ind3);
tmpDOW = TCdd.toInt();
tmpTChour = inTC.substring(ind3 + 1, ind4);
tmpTCminute = inTC.substring(ind4 + 1, ind5);
//tmpOnceTCepoch = inTC.substring(ind5 + 1, ind6);
//tmpisOnce = inTC.substring(ind6 + 1);
parsed2html = "<b>" + String(inLine) + ".&nbsp;type:</b>" + tmpAlarmType + "&nbsp;&nbsp;<b>command:</b>";
parsed2html += String(TCommandsFNames[tmpTCommand]);
if (tmpDOW > 0) parsed2html += "&nbsp;&nbsp;<b>day:</b>" + String(dayStr(tmpDOW));
parsed2html += "&nbsp;&nbsp;<b>hour:</b>" + String(tmpTChour) + "&nbsp;&nbsp;<b>minute:</b>" + tmpTCminute + "<br><br>";
return parsed2html;
}
// -------------------------------- END ALARM functions ---------------------------------
// -------------------------------- START server functions ---------------------------------
// Timestamp function for the web interface
String timestamp() {
if (NTPsuccess) {
String theday = dayStr(weekday());
String themonth = monthStr(month());
return "<br><br><p>local time timestamp: <b>" + theday + ", " + String(day()) + " " + themonth + " " + String(year()) + "</b> -- <b>" + calcDigits(hour()) + ":" + calcDigits(minute()) + ":" + calcDigits(second()) + "</b></p>\n";
} else return FPSTR(NTPfail);
}
// When the Restart button is pressed at the web interface
void handle_restart() {
String tmppinstate;
tmppinstate = pinstate;
pinstate = F("<b>Please wait a few seconds.<br>! Device will reboot !</b><br><br>");
pinstate += tmppinstate;
delay(100);
handle_root();
delay(500);
handle_APrestart();
}
// Main Time Commands web interface
void handle_timecommands() {
String SServerSend;
SServerSend = webPageHeader("THE433 TimeCommands control", "THE433 TimeCommands control", "#333", "#fff");
if (NTPsuccess) {
SServerSend += TCsubmitResult + SPIFFSstatus + "<br>";
SServerSend += FPSTR(webPageTC_0);
SServerSend += F("<b>You can add up to&nbsp;");
SServerSend += MAXTCommands;
SServerSend += F("&nbsp;Time Commands</b>");
SServerSend += FPSTR(webPageTC_1);
SServerSend += TCommandsCall();
SServerSend += FPSTR(webPageTC_2);
}
SServerSend += timestamp();
SServerSend += FPSTR(webPageHomeButton);
if (NTPsuccess) SServerSend += FPSTR(SPIFFSTCommandsList_1);
if (NTPsuccess) SServerSend += SPIFFSTCommandsList;
if (NTPsuccess) SServerSend += FPSTR(SPIFFSTCommandsList_2);
if (NTPsuccess) SServerSend += FPSTR(webPageClearTCButton);
SServerSend += FPSTR(webPageRestartButton);
SServerSend += webPageFooter;
delay(100);
server.send(200, "text/html", SServerSend);
}
// When a new Time Command is added from the web interface
void handle_TCsubmit() {
String state = server.arg("tmcommand");
if (countTCommands < MAXTCommands) {
int TCommandPos = -1;
for (int i = 0; i < numAvailFuncs; ++i) {
if (state == TCommandsFNames[i]) {
TCommandPos = i;
}
}
if (TCommandPos == -1) {
TCsubmitResult = F("Command not found!");
} else {
if ((server.arg("AlarmType") == "") || (server.arg("tchour") == "") || (server.arg("tcminutes") == "")) {
TCsubmitResult = F("Wrong or no selection in Schedule or Time!");
} else if (((server.arg("tcdow") == "") || (server.arg("tcdow") == "nodow")) && ((server.arg("AlarmType") == "AlarmRepeatDOW") || (server.arg("AlarmType") == "AlarmOnceDOW"))) {
TCsubmitResult = F("You have to select a Day with that alarm type!");
} else if (((server.arg("tchour").toInt() >= 0) && (server.arg("tchour").toInt() < 24)) || ((server.arg("tcminutes").toInt() >= 0) && (server.arg("tcminutes").toInt() < 59))) {
String S2Write;
int s2d, s2h, s2m;
s2d = server.arg("tcdow").toInt();
s2h = server.arg("tchour").toInt();
s2m = server.arg("tcminutes").toInt();
S2Write = String(TCommandPos) + TCSaveFileDelimiter;
S2Write += server.arg("AlarmType") + TCSaveFileDelimiter;
if ((server.arg("AlarmType") == "AlarmRepeatDaily") || (server.arg("AlarmType") == "AlarmOnce")) {
S2Write += "nodow";
S2Write += TCSaveFileDelimiter;
} else S2Write += server.arg("tcdow") + TCSaveFileDelimiter;
S2Write += server.arg("tchour") + TCSaveFileDelimiter;
S2Write += server.arg("tcminutes") + TCSaveFileDelimiter;
time_t s_tm;
if (server.arg("AlarmType") == "AlarmOnce") {
if (s2h > hour()) {
s_tm = tmConvert_t(year(), month(), day(), s2h, s2m, 0);
} else if ((s2h == hour()) && (s2m > minute())) {
s_tm = tmConvert_t(year(), month(), day(), s2h, s2m, 0);
} else {
s_tm = tmConvert_t(year(), month(), day() + 1, s2h, s2m, 0);
}
S2Write += String(s_tm) + String(TCSaveFileDelimiter) + "1";
} else if (server.arg("AlarmType") == "AlarmOnceDOW") {
if (s2d == weekday()) {
if (s2h > hour()) {
s_tm = tmConvert_t(year(), month(), day(), s2h, s2m, 0);
} else if ((s2h == hour()) && (s2m > minute())) {
s_tm = tmConvert_t(year(), month(), day(), s2h, s2m, 0);
} else {
s_tm = tmConvert_t(year(), month(), day() + 7, s2h, s2m, 0);
}
} else {
int s2dd = s2d - weekday();
if (s2dd < 0) {
s2dd = s2dd + 7;
}
s_tm = tmConvert_t(year(), month(), day() + s2dd, s2h, s2m, 0);
}
S2Write += String(s_tm) + String(TCSaveFileDelimiter) + "1";
} else S2Write += "0" + String(TCSaveFileDelimiter) + "0";
writeSpiffsTC(S2Write);
}
}
} else {
TCsubmitResult = F("Up to ");
TCsubmitResult += MAXTCommands;
TCsubmitResult += F(" TimeCommands are allowed!");
}
delay(100);
handle_timecommands();
}
// Execute Time Command remove from save file from web interface
void handle_TCsubmitRemove() {
delay(100);
if (server.arg("TC2Remove") != "") {
RemoveLinesSpiffsTC(server.arg("TC2Remove"));
} else TCsubmitResult = F("No Time Command selected to delete!");
delay(100);
handle_timecommands();
}
// Main web page for controling 433MHz switches directly
void handle_root() {
String SServerSend;
SServerSend = webPageHeader("THE433 control", "THE433 control", "#000", "#fff") + pinstate;
SServerSend += FPSTR(webPage433form);
SServerSend += timestamp();
SServerSend += SPIFFSstatus;
SServerSend += FPSTR(webPageHomeButton);
SServerSend += webPageFooter;
server.send(200, "text/html", SServerSend);
}
// Form of the main web page, activates a 433MHz switch or enters Time Commands interface
void handle_submit() {
String state = server.arg("pin");
if (state == TCOMMANDWORD) { //"ENTERTIMECOMMANDS"
delay(1000);
handle_timecommands();
} else {
int TCommandPos = -1;
for (int i = 0; i < numAvailFuncs; ++i) {
if (state == TCommandsFNames[i]) {
TCommandPos = i;
}
}
if (TCommandPos != -1) {
TCommandsFunctions[TCommandPos]();
delay(3000);
handle_root();
} else {
pinstate = F("<h2>-</h2>");
digitalWrite(ONBOARDLED, HIGH);
delay(3000);
handle_root();
}
}
}
// -------------------------------- END server functions ---------------------------------
// -------------------------------- START SPIFFS functions ---------------------------------
// Format SPIFFS of esp8266, not accessible from the web interface
void formatspiffs() {
String SServerSend;
SServerSend = webPageHeader("THE433 control", "THE433 control", "#000", "#fff");
SServerSend += F("<h2>! formatting SPIFFS !<br>Please wait 30 seconds.<br>! Device will reboot then !</h2>");
SServerSend += timestamp();
SServerSend += webPageFooter;
server.send(200, "text/html", SServerSend);
SPIFFS.begin();
SPIFFS.format();
delay(30000);
Serial.println(F("SPIFFS formatted!"));
handle_APrestart();
}
// Deletes the TCSaveFile that Time Commands are stored in from SPIFFS
void removeTCSaveFile() {
SPIFFS.remove(TCSaveFile);
delay(1000);
Serial.println(TCSaveFile " removed.");
//handle_APrestart();
handle_restart();
}
// Reads the TCSaveFile that Time Commands are stored in from SPIFFS
// at boot and sets the needed Alarm timers.
// Also lists stored Time Commands for the web interface
void readSpiffsTC() {
SPIFFSstatus = "";
SPIFFSTCommandsList = "";
if (SPIFFS.begin()) {
SPIFFSstatus = F("SPIFFS mounted.\n");
Serial.println(SPIFFSstatus);
if (SPIFFS.exists(TCSaveFile)) {
Serial.println("reading " TCSaveFile);
File TCconfigFile = SPIFFS.open(TCSaveFile, "r");
if (TCconfigFile) {
SPIFFSTCommandsList = FPSTR(SPIFFSTCommandsList_3);
Serial.println("opened " TCSaveFile);
while (TCconfigFile.available()) {
String line = TCconfigFile.readStringUntil('\n');
line.replace("\n", "");
line.trim();
Serial.println(line);
countTCommands++;
parseTC(line, countTCommands);
delay(100);
SPIFFSTCommandsList += FPSTR(SPIFFSTCommandsList_4);
SPIFFSTCommandsList += line + "\">&nbsp;&nbsp;";
SPIFFSTCommandsList += parseTC2HTML(line, countTCommands);
SPIFFSTCommandsList += "</li>";
delay(100);
}
SPIFFSstatus += " " + String(countTCommands) + " commands read.\n";
SPIFFSTCommandsList += FPSTR(SPIFFSTCommandsList_5);
} else {
Serial.println("Error opening " TCSaveFile "!");
SPIFFSstatus = "Error opening " TCSaveFile "!\n";
}
TCconfigFile.close();
} else {
Serial.println(TCSaveFile " not found!");
SPIFFSstatus += F(" TimeCommands file not found!\n");
}
} else {
SPIFFSstatus = F("SPIFFS mount failed!\n");
}
SPIFFSstatus = "<p>" + SPIFFSstatus + "</p>\n";
}
// Writes a newly entered Time Command in TCSaveFile stored in SPIFFS
void writeSpiffsTC(String inputline) {
TCsubmitResult = "";
File TCconfigFile = SPIFFS.open(TCSaveFile, "a");
if (!TCconfigFile) {
Serial.println(TCSaveFile " doesn't exist yet. Creating it");
File TCconfigFile = SPIFFS.open(TCSaveFile, "w");
if (!TCconfigFile) {
Serial.println(TCSaveFile "file creation failed!!!");
TCsubmitResult = TCSaveFile "file creation failed!!!";
return;
}
}
TCconfigFile.println(inputline);
delay(100);
TCconfigFile.close();
TCsubmitResult = "TimeCommand written in " TCSaveFile;
TCsubmitResult += FPSTR(esprestartmsg);
TCsubmitResult += FPSTR(webPageRestartButton);
}
// Removes a given line from TCSaveFile
void RemoveLinesSpiffsTC(String Line2Remove) {
TCsubmitResult = "";
if (SPIFFS.begin()) {
SPIFFSstatus = F("SPIFFS mounted.\n");
Serial.println(SPIFFSstatus);
if (SPIFFS.exists(TCSaveFile)) {
Serial.println("reading " TCSaveFile);
File TCconfigFile = SPIFFS.open(TCSaveFile, "r");
File tempTCconfigFile = SPIFFS.open("/TCconfig.temp", "w");
if (!TCconfigFile || !tempTCconfigFile) {
Serial.println(F("/TCconfig.temp file creation failed!!! Aborting!"));
TCsubmitResult = F("/TCconfig.temp file creation failed!!! Aborting!");
return;
}
Serial.println("opened " TCSaveFile);
Serial.println(F("opened /TCconfig.temp"));
while (TCconfigFile.available()) {
String line = TCconfigFile.readStringUntil('\n');
line.replace("\n", "");
line.trim();
if (Line2Remove != line) {
Serial.println(line);
tempTCconfigFile.println(line);
}
delay(100);
}
Serial.println(F("/TCconfig.temp written."));
delay(10);
// close files
tempTCconfigFile.close();
TCconfigFile.close();
// replace config file
if (SPIFFS.exists("/TCconfig.temp")) {
SPIFFS.remove(TCSaveFile);
delay(100);
Serial.println(TCSaveFile " removed.");
SPIFFS.rename("/TCconfig.temp", TCSaveFile);
if (SPIFFS.exists(TCSaveFile)) {
Serial.println(TCSaveFile " replaced.");
TCsubmitResult = "TimeCommand removed!";
TCsubmitResult += FPSTR(esprestartmsg);
TCsubmitResult += FPSTR(webPageRestartButton);
}
}
} else {
Serial.println(TCSaveFile " not found!");
SPIFFSstatus += F(" TimeCommands file not found!\n");
}
} else {
SPIFFSstatus = F("SPIFFS mount failed!\n");
}
SPIFFSstatus = "<p>" + SPIFFSstatus + "</p>\n";
}
// -------------------------------- END SPIFFS functions ---------------------------------
// -------------------------------- setup & loop ---------------------------------
void setup(void) {
pinMode(ONBOARDLED, OUTPUT);
byte ledStatus = HIGH;
countTCommands = 0;
mySwitch.enableTransmit(RCSwitchPin);
Serial.begin(57600);
WiFi.mode(WIFI_STA);
// uncomment the following if you set a static IP in the begining
WiFi.config(nkip, nkgateway, nksubnet);
// call espWiFi2eeprom to connect to saved to eeprom AP or
// to create an AP to store new values for SSID and password
espNKWiFiconnect();
//--
Serial.print(F("IP address: "));
Serial.println(WiFi.localIP());
// espWiFi2eeprom: with the two following you can restart or clear eeprom
// from your main esp8266 server
server.on(restartcommand, handle_APrestart);
server.on(cleareepromcommand, handle_clearAPeeprom);
//--
// get NTP time and convert it to local
// NKNTP.h and NKNTP.ino files must be present
// in NKNTP.h you can set your time zone and DST
NTP2localTime();
digitalWrite(ONBOARDLED, HIGH);
delay(100);
// Empty array of Time Commands at boot
nullFillalarmepochs();
delay(100);
// If we got NTP time then Time Commands are available
if (NTPsuccess) {
readSpiffsTC();
server.on("/TCsubmit", handle_TCsubmit);
server.on("/removeTCSaveFile", removeTCSaveFile);
server.on("/formatspiffs", formatspiffs);
server.on("/TClistdelline", handle_TCsubmitRemove);
}
server.on("/esp433restart", handle_restart);
server.on("/", handle_root);
server.on("/submit", handle_submit);
server.begin();
// If we got NTP time set up the cleanup function of Once only executed Time Commands
if (NTPsuccess) {
delay(100);
Alarm.timerRepeat(33 * 60, CleanupTC); // (minutes * seconds) that must have passed in order to clean the alarm events
Alarm.delay(0);
Serial.println("Cleanup set");
}
Serial.println(F("HTTP server started"));
//debug
//for (int i = 0; i <= 10; i++) Serial.println(Alarm.read(i));
}
void loop(void) {
server.handleClient();
// the following is needed for the TimeAlarms libray
Alarm.delay(0);
}

16
espWiFi2eeprom.h Normal file
View File

@ -0,0 +1,16 @@
// you should change the following two to something of your own to remember
#define AP_RESTART "esprestart"
#define AP_CLEAREEPROM "cleareeprom"
#define AP_WIFICFGPORT 8266
//--
// password for the esp8266 softAP creates when it doesn't find info in the eeprom
// or when something else goes wrong and can't connect
const char AP_password[] = "esp8266control";
//--
#define ESPWIFI2EEPROM_VERSION "0.4"
void espNKWiFiconnect();
void handle_APrestart();
void handle_clearAPeeprom();
extern const char* restartcommand;
extern const char* cleareepromcommand;

340
espWiFi2eeprom.ino Normal file
View File

@ -0,0 +1,340 @@
/*
"esp8266 WiFi configuration to eeprom manager for Arduino IDE"
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
- idea and some code parts from chriscook8 esp-arduino-apboot https://github.com/chriscook8/esp-arduino-apboot
- sort by RSSI by tablatronix https://github.com/esp8266/Arduino/issues/1355
- thanks goes to fivosv for his patience to help me
----------------
Check example-espWiFi2eeprom.ino for an example of usage along with another server.
You can edit espWiFi2eeprom.h in order to change parameters.
--------------------------------------------------------------------------------
*/
#include <ESP8266WiFi.h>
#include <ESP8266Webserver.h>
#include <EEPROM.h>
// defined in espWiFi2eeprom.h , keywords to restart or clear eeprom
const char* restartcommand = "/" AP_RESTART;
const char* cleareepromcommand = "/" AP_CLEAREEPROM;
ESP8266WebServer APserver(AP_WIFICFGPORT);
// web page parts
const char APwebPage1[] PROGMEM = "<!DOCTYPE HTML>\n"
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><title>esp8266 WiFi setup control</title>\n"
"<style type=\"text/css\">body {text-align:center;font-family: sans-serif;background-color: #000;color: #fff;font-size:1.2em;} a:link, a:visited, a:hover, a:active {color:#fff;}</style>\n"
"</head>\n"
"<body>\n"
"<h1>esp8266 WiFi setup control</h1>\n<br>"
"<table style=\"width:100%;border: 1px solid #fff;\"><tr>"
"<th style=\"text-align:center;width:50%;\"><form action='/APsubmit' method='POST'><input type=\"text\" name=\"newssid\" id=\"formnewssid\" value=\"\"><br><input type=\"text\" name=\"newpass\" value=\"\" size=\"32\" maxlength=\"64\"><br><input type=\"submit\" value=\"Submit\"></form></th>"
"<th style=\"text-align:left;width:50%;\">";
String APwebPage2 = "</th></tr></table>\n"
"<br><br><form action=\"/\" target=\"_top\"><input type=\"submit\" value=\"home / rescan networks\"></form>\n"
"<br><br><form action=\"" + String(restartcommand) + "\" target=\"_top\"><input type=\"submit\" value=\"restart esp8266\"></form>\n"
"<br><br><form action=\"" + String(cleareepromcommand) + "\" target=\"_top\"><input type=\"submit\" value=\"! clear EEPROM !\"></form>\n"
"<br><br><b>- version: " ESPWIFI2EEPROM_VERSION " -</b>\n"
"</body></html>";
String APwebstring = ""; // String to display
// clear first bytes of eeprom
void handle_clearAPeeprom() {
Serial.println(F("! Clearing eeprom !"));
for (int i = 0; i < 96; ++i) {
EEPROM.write(i, 0);
}
EEPROM.commit();
delay(1000);
ESP.restart();
}
// restart esp8266
void handle_APrestart() {
Serial.println(F("! Restarting in 1 sec! !"));
delay(1000);
ESP.restart();
}
// responds to local server / call
void handle_AProot() {
getAPlist();
String SServerSend;
SServerSend = FPSTR(APwebPage1);
SServerSend += APwebstring + APwebPage2;
APserver.send(200, "text/html", SServerSend);
delay(100);
}
// when the form with ssid and pass is submited write them to eeprom
void handle_APsubmit() {
String thenewssid = APserver.arg("newssid");
String thenewpass = APserver.arg("newpass");
if (thenewssid != "") {
Serial.println(F("! Clearing eeprom !"));
for (int i = 0; i < 96; ++i) {
EEPROM.write(i, 0);
}
Serial.println(F("Writing SSID to EEPROM"));
for (int i = 0; i < thenewssid.length(); ++i)
{
EEPROM.write(i, thenewssid[i]);
//Serial.print("Wrote: ");
//Serial.println(thenewssid[i]);
}
Serial.println(F("Writing password to EEPROM"));
for (int i = 0; i < thenewpass.length(); ++i)
{
EEPROM.write(32 + i, thenewpass[i]);
//Serial.print("Wrote: ");
//Serial.println(thenewpass[i]);
}
if (EEPROM.commit()) {
APwebstring = F("<h2><b><p>Saved to eeprom... restart to boot into new wifi</b></h2>\n");
} else {
APwebstring = F("<h2><b><p>Couldn't write to eeprom. Please try again.</b></h2>\n");
}
delay(10);
String SServerSend;
SServerSend = FPSTR(APwebPage1);
SServerSend += APwebstring + APwebPage2;
APserver.send(200, "text/html", SServerSend);
delay(100);
}
}
// return the connection type for the AP list
String printConnectionType(int thisType) {
String con_type = "";
// read connection type and print out the name:
switch (thisType) {
case 255:
return con_type = "WL_NO_SHIELD";
case 0:
return con_type = "WL_IDLE_STATUS";
case 1:
return con_type = "WL_NO_SSID_AVAIL";
case 2:
return con_type = "WL_SCAN_COMPLETED";
case 3:
return con_type = "WL_CONNECTED";
case 4:
return con_type = "WL_CONNECT_FAILED";
case 5:
return con_type = "WL_CONNECTION_LOST";
case 6:
return con_type = "WL_DISCONNECTED";
default:
return con_type = "?";
}
}
// return the connection type for the AP list
String printEncryptionType(int thisType) {
String enc_type = "";
// read the encryption type and print out the name:
switch (thisType) {
case ENC_TYPE_WEP:
return enc_type = "WEP";
case ENC_TYPE_TKIP:
return enc_type = "WPA";
case ENC_TYPE_CCMP:
return enc_type = "WPA2";
case ENC_TYPE_NONE:
return enc_type = "None";
case ENC_TYPE_AUTO:
return enc_type = "Auto";
default:
return enc_type = "?";
}
}
// test if we are connected
boolean testWiFi() {
int c = 0;
Serial.print(F("Waiting for Wifi to connect"));
// c at 60 with delay 500 is for 30 seconds ;)
while ( c < 60 ) {
Serial.print(".");
if (WiFi.status() == WL_CONNECTED) {
Serial.println("");
Serial.println(printConnectionType(WiFi.status()));
return 1;
}
delay(500);
c++;
}
Serial.println("");
Serial.println(printConnectionType(WiFi.status()));
return 0;
}
// get available AP to connect + HTML list to display
void getAPlist() {
WiFi.disconnect();
delay(100);
int n = WiFi.scanNetworks();
Serial.println(F("Scan done"));
if (n == 0) {
Serial.println(F("No networks found :("));
APwebstring = F("No networks found :(");
return;
}
// sort by RSSI
int indices[n];
for (int i = 0; i < n; i++) {
indices[i] = i;
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) {
std::swap(indices[i], indices[j]);
}
}
}
Serial.println("");
// HTML Print SSID and RSSI for each network found
APwebstring = F("<ul>");
for (int i = 0; i < n; ++i)
{
APwebstring += F("<li>");
APwebstring += i + 1;
APwebstring += F(":&nbsp;&nbsp;<b>");
APwebstring += F("<a href=\"#\" target=\"_top\" onClick=\"document.getElementById(\'formnewssid\').value=\'");
APwebstring += WiFi.SSID(indices[i]);
APwebstring += F("\'\">");
APwebstring += WiFi.SSID(indices[i]);
APwebstring += F("</a>");
APwebstring += F("</b>&nbsp;&nbsp;&nbsp;(");
APwebstring += WiFi.RSSI(indices[i]);
APwebstring += F("&nbsp;dBm)&nbsp;&nbsp;&nbsp;");
APwebstring += printEncryptionType(WiFi.encryptionType(indices[i]));
APwebstring += F("</li>");
}
APwebstring += F("</ul>");
delay(100);
}
// setup a soft AP for the user to connect to esp8266 and give a new ssid and pass
void setupWiFiAP() {
WiFi.mode(WIFI_AP);
// Do a little work to get a unique-ish name for the soft AP. Append the
// last two bytes of the MAC (HEX'd):
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
macID.toUpperCase();
String AP_NameString = F("esp8266 control ");
AP_NameString += macID;
char AP_NameChar[AP_NameString.length() + 1];
memset(AP_NameChar, 0, AP_NameString.length() + 1);
for (int i = 0; i < AP_NameString.length(); i++)
AP_NameChar[i] = AP_NameString.charAt(i);
getAPlist();
APserver.on("/", handle_AProot);
APserver.on("/APsubmit", handle_APsubmit);
APserver.on(restartcommand, handle_APrestart);
APserver.on(cleareepromcommand, handle_clearAPeeprom);
WiFi.softAP(AP_NameChar, AP_password);
APserver.begin();
Serial.print(F("SoftAP IP address: "));
Serial.println(WiFi.softAPIP());
while (WiFi.status() != WL_CONNECTED) {
APserver.handleClient();
}
}
// main function called externally
void espNKWiFiconnect() {
WiFi.mode(WIFI_STA);
EEPROM.begin(512);
Serial.println("");
// read eeprom for ssid and pass
Serial.println(F("Reading EEPROM SSID"));
String esid = "";
for (int i = 0; i < 32; ++i)
{
esid += char(EEPROM.read(i));
}
//Serial.print("SSID: ");
//Serial.println(esid);
Serial.println(F("Reading EEPROM password"));
String epass = "";
for (int i = 32; i < 96; ++i)
{
epass += char(EEPROM.read(i));
}
//Serial.print("PASS: ");
//Serial.println(epass);
// if ssid not empty try to connect
if (esid != "") {
// test esid
WiFi.begin(esid.c_str(), epass.c_str());
boolean testWiFiAP = testWiFi();
if (testWiFiAP) {
return;
} else if (!testWiFiAP) {
Serial.println(F("Could not connect to SSID!"));
if (WiFi.status() == WL_CONNECT_FAILED) {
// we found the AP but connection failed. maybe pass is wrong.
// clear eeprom and restart esp so we can try again
Serial.println(F("Connection failed! Maybe SSID/password are wrong."));
Serial.println(F("Clearing EEPROM and restarting!"));
delay(500);
handle_clearAPeeprom();
delay(100);
handle_APrestart();
} else {
// could not connect to ssid so starting soft AP
Serial.println("Starting AP at port: " + String(AP_WIFICFGPORT));
setupWiFiAP();
}
}
} else {
// ssid not found in eeprom so starting soft AP
Serial.println("SSID empty! Starting AP at port: " + String(AP_WIFICFGPORT));
setupWiFiAP();
}
}