Major update/rewrite/recombine to get SSDP, and GrowController UI and application shell.

This commit is contained in:
David
2021-10-25 23:46:03 +00:00
parent c47c37a891
commit 4597350845
52 changed files with 4981 additions and 4990 deletions

View File

@@ -1,847 +1,144 @@
///
///
/// Grow Controller
///
///
/// The beginnings of a WiFi accessible switch.
///
#include <dummy.h>
#include <tcp_axtls.h>
#include <SyncClient.h>
#include <ESPAsyncTCPbuffer.h>
#include <ESPAsyncTCP.h>
#include <async_config.h>
#include <AsyncPrinter.h>
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266httpUpdate.h>
//#include <ESP8266mDNS.h>
#include <ESP8266SSDP.h>
#include "ProjGlobals.h" // Some global settings
#include "WiFiConfiguration.h" //
#include "WiFiStateHandler.h" // Startup as AP or client and transition
#include "CustomHandlers.h" // Handlers for the web pages
#include "PlantModel.h" // The Plant Model controller/simulator/status
const String AP_NAME = "GrowController"; ///< Network name when in Access Point mode
const String AP_VERS = "v1.00.11"; ///< Compared to the server version for SW Updates
ESP8266WebServer server(80);
ConfigManager wifiConfig; ///< Track various configuration items
//ESP8266HTTPUpdate Updater;
bool updateCheck = false; ///< Set when a SW update check is pending
// Application includes
#include "./DNSServer.h" // Patched lib
#include "WiFiConfiguration.h"
#include "Web_RootPage.h"
#include "Web_RSSIGraph.h"
#include "Web_FavIcon.h"
#include "Web_APConfig.h"
#include "ProjGlobals.h"
#include "Web_Resources.h"
#include "GrowController.h" // APIs available in this (.ino) file
#include "fauxmoESP.h"
// If there is no hardware, such as with an ESP-01 module only,
// set this. Then it won't loop through reset constantly, and
// other behaviors that will be determined.
#define HW_SIMULATE
// SW Update Deployment instructions:
// Register the urls with custom handlers
// Register the SSDP interface
//
// 1) If any resources changed, rebuild Web_Resources.h
// 2) Update this version number
// 3) Build the binary
// 4) Rename the .bin to match the version (e.g. GrowController v1.02.12.bin)
// 5) Move the product (.bin) to the server location
// 6) Update the PHP script on the server to match this version (if it does not auto-adapt)
// 7) Visit the node's web page and initiate an update, or let it check on its own cycle
//
const String MyVer = "GrowController v2.00.11"; ///< Compared to the server version for SW Updates
#define UPDATE_INTERVAL (12 * 60 * 60 * 1000) ///< Check once every 12 hours
bool swUpdateInProcess = false; ///< Status of an update to keep the relays from running
// ESP12-E pinout Version 2
//
// +------------------+
// | __ __ _____ |
// | | |_| |_| |
// | |__________ |
// |__________________|
// Reset | !Reset Tx | Tx
// Current | ADC Rx | Rx
// Prog En | CHPD-EN GPIO5 | FAULT
// SW_RESET | GPIO16 GPIO4 | SW_TOGGLE
// OLED SCL | GPIO14 GPIO0 |
// RLY Set2 | GPIO12 GPIO2 | OLED SDA
// RLY Set1 | GPIO13 GPIO15 | Pull-down
// | Vcc Gnd |
// +------------------+
// ESP12-E pinout Version 1
//
// +------------------+
// | __ __ _____ |
// | | |_| |_| |
// | |__________ |
// |__________________|
// Reset | !Reset Tx | Tx
// Current | ADC Rx | Rx
// Prog En | CHPD-EN GPIO5 |
// SW_RESET | GPIO16 GPIO4 | SW_TOGGLE
// RLY Set2 | GPIO14 GPIO0 |
// LED On | GPIO12 GPIO2 |
// RLY Set1 | GPIO13 GPIO15 | LED WiFi
// | Vcc Gnd |
// +------------------+
// +-------------+
// SW_RESET ---+----|(----------->| WiFiConfig |-----> LED_WIFI
// | | |
// | | |-----> isStationMode
// | |-------------|
// +----|>o---------->| Timer |
// | |-----> Factory Reset
// RESET_MS --------------------->| |
// +-------------+
//
#define SW_RESET 16 ///< The local reset switch
#define RESET_MS 8000 ///< Hold Reset for this long to factory reset
#define LED_WIFI 15 ///< The Pin controlling the WiFi on LED
bool isStationMode = false; ///< Tracks if the WiFi is in station mode
// WiFI LED Duty Cycle
//
// |******* | AP Mode
// |************************* | Joining AP
// |************************************************ | Joined
// | | | | | |
// 0 100 200 300 400 500ms
//
#define LED_APMODE__MS 80
#define LED_JOINING_MS 250
#define LED_JOINED__MS 490
#define LED_PERIOD__MS 500
// __ //
// | \ //
// onRef ------------------------------|- \ +-----------+ //
// | +-----| S Q |--+--> CurrStatus //
// +--------|+ / | | | //
// +---------+ | |__/ +--| R !Q | +--> LED_ON //
// ANA_IN --+--->| average |----+-->iRawSum/X | +-----------+ //
// | +---------+ | __ | //
// | | | \ | //
// +--> iRaw +--------|- \ | //
// | +--+ //
// offRef ------------------------------|+ / //
// |__/ //
//
#define ANA_IN A0 ///< The Analog input signal
#define SENSE_SAMPLE_MS 20 ///< The Sample rate for the analog input
#define AVG_RATIO 64 ///< Average Ratio (new is 1/AVG_RATIO of old)
#define LED_ON 12 ///< The load-on indicating LED
int32_t iRaw; ///< The raw sampled value
int32_t iRawSum; ///< The Averaged Sum of Raw Samples
bool CurrStatus = false; ///< Track the current sense indication of power on/off
void StartWebServer();
// _ +------------------+
// Turn On -------------| \____ | +-----------+ |
// +--|>o--|_/ | _ +-->| D !Q |--+
// CurrStatus --| and +-------->) \ | |
// | _ +-------->) +--->| ck Q |--------> RelayState
// +-------| \____| +---->)_/ +-----------+
// Turn Off-------------|_/ | or
// and |
// SW_TOGGLE ----|>o---------------+
//
#define SW_TOGGLE 4 ///< The local toggle switch
bool RelayState = false; ///< The current tracked relay drive state
// +-----------+
// | _ _ |
// | _/ _| |_ |--------> Relay Set
// RelayState ---------------------------------->| _ _ |
// | \_ _| |_ |--------> Relay Reset
// | |
// +-----------+
//
#define RELAY_PULSE_MS 15 ///< Duration of a pulse
#define RLY_SET1 13 ///< The set-pin for the relay
#define RLY_SET2 14 ///< The reset-pin for the relay
// Timing:
//
// | | | | |
// _________________________
// 3WaySwitch ____________________/ \__________________
// | | |b->| | |b->|
// ______________________
// RelayState __________/ \______________________
// | |a->| | |a->| |
// | | | | |
// +++++++ ++++++++++
// +++ +++ +++ +++
// AnalogIn ++++++++++++ ++++++++++ +++++++++++++++
// | | | | |
// CurrStatus |Off |On |Off |On |Off
//
// a) Locally applied change in load to filtered AnalogIn delay
// b) Externally applied change in load to filtered AnalogIn delay
//
bool DebugValue; ///< Makes it chatty while running
const byte DNS_PORT = 53; ///< Capture DNS requests on port 53
IPAddress apIP(192,168,4,1); ///< Private network for server
DNSServer dnsServer; ///< Create the DNS object
ESP8266WebServer server(80); ///< For the user experience
fauxmoESP fauxmo; ///< For the WEMO emulator
ConfigManager wifiConfig; ///< Track various configuration items
ESP8266HTTPUpdate Updater;
bool updateCheck = false; ///< Set when a SW update check is pending
uint16_t autoOffTimer; ///< When the output is turned on, this is set to timeout in seconds
// local functions
void WiFiStateHandler(); ///< WiFi interface manager
void StartWebServer(); ///< Activate the web server
void HandleNotFound(); ///< Webpage for not-found URL
void ProcessAutoOff(bool init = false); ///< Process the auto-off timer
String AP_SSID = "GrowController"; ///< When in Access Point, this is the prefix
void GetMac();
String macToStr(const uint8_t* mac); ///< Create C++ String with the mac
String clientMac = ""; ///< Hosts the MAC to easily identify this node
// ===========================================================================
typedef enum {
WFC_ConnectToAP,
WFC_JoiningAP,
WFC_JoinedAP,
WFC_CreateAP,
WFC_HostingAP,
} WiFiConnectState;
WiFiConnectState wifiConState; ///< Track the current WiFi state
void SetLED(int pin, int state) {
digitalWrite(pin, state);
if (pin == LED_WIFI)
; // Serial.printf("SET LED_WIFI to %d\n", state);
else if (pin == LED_ON)
Serial.printf("SET LED_ON to %d\n", state);
else
Serial.printf("***** ERROR setting LED pin %d to %d\n", pin, state);
}
void ResetMonitor(bool init = false) {
static unsigned long timeAtReset;
static bool monitorActive;
if (init) {
timeAtReset = millis();
monitorActive = true;
} else if (monitorActive) {
int sw_state = digitalRead(SW_RESET);
#ifdef HW_SIMULATE
sw_state = 1;
#endif
if (sw_state == 1) {
// not pressed
monitorActive = false;
} else if ((millis() - timeAtReset) > RESET_MS) {
// reset has been held long enough
FactoryReset(true);
}
}
}
//
// Average the new sample by summation with 7/8 of the running Sum.
//
void ProcessCurrentSense() {
static unsigned long last = millis();
unsigned long now = millis();
if (now - last > SENSE_SAMPLE_MS) {
last = now;
iRaw = analogRead(ANA_IN); // 1023 = 1.0v
iRawSum = iRawSum - (iRawSum / AVG_RATIO) + iRaw; // Now have running avg.
if (DebugValue)
Serial.printf("Sample: %d, rawSum: %d, relay: %d (%d%d), \n",
iRaw, iRawSum, RelayState, digitalRead(RLY_SET1), digitalRead(RLY_SET2));
if (iRawSum / AVG_RATIO > wifiConfig.getOnRef() && !CurrStatus) {
CurrStatus = true;
SetLED(LED_ON, 1);
ProcessAutoOff(true);
autoOffTimer = wifiConfig.getAutoOff(); // if zero, we do nothing...
Serial.printf("Auto Off Timer set to %d\n", autoOffTimer);
} else if (iRawSum / AVG_RATIO < wifiConfig.getOffRef() && CurrStatus) {
CurrStatus = false;
SetLED(LED_ON, 0);
}
}
}
// _______ ___ __ _______
// Press \_________________________/ \___/ \___/
// | |
// v v
// _ _
// Toggle _______/ \____________.............../ \______________....
//
// Sample | | | | | ...
// Block |---- 80 ms ---| |---- 80 ms -----|
#define Block_ms 800
#define SAMPL_ms 100
void ProcessToggleSw() {
static unsigned long last = millis();
static bool lastSWState = false;
static uint8_t blockTics;
unsigned long now = millis();
if (now - last > SAMPL_ms) {
last = now;
if (blockTics) {
blockTics--;
return;
}
bool swState = !digitalRead(SW_TOGGLE); // active low is pressed.
if (DebugValue)
Serial.printf("Sample: %d, rawSum: %d, relay: %d (%d%d), sw: %d\n",
iRaw, iRawSum, RelayState, digitalRead(RLY_SET1), digitalRead(RLY_SET2), swState);
if (swState != lastSWState && swState == true) {
Serial.printf("Toggle pushed\n");
blockTics = Block_ms / SAMPL_ms;
SetCircuit(CMD_Toggle);
}
lastSWState = swState;
}
}
// Drive Relay controls pulsing either the set or the reset pin
//
// If the control signal changes, then it will generate a pulse on the
// appropriate relay driver pin, ensuring that the alternate pin is
// first off.
//
// This API is also called periodically, which permits it to then
// time and auto-off any active control pin.
//
// @param i can be -1 for timing, 0 to drive one relay pin, 1 to drive the other.
//
void DriveRelay(int i = -1) {
static int currentSignal = -1;
static bool isActive = false;
static unsigned long timeSet = 0;
if (swUpdateInProcess)
i = 2;
switch (i) {
case -1:
// Any active timing to process
if (isActive && (millis() - timeSet > RELAY_PULSE_MS)) {
digitalWrite(RLY_SET1, LOW);
digitalWrite(RLY_SET2, LOW);
isActive = false;
}
break;
case 0:
if (i != currentSignal) {
currentSignal = i;
digitalWrite(RLY_SET2, LOW); // Turn off the alternate
digitalWrite(RLY_SET1, HIGH);
timeSet = millis();
isActive = true;
}
break;
case 1:
if (i != currentSignal) {
currentSignal = i;
digitalWrite(RLY_SET1, LOW); // Turn off the alternate
digitalWrite(RLY_SET2, HIGH);
timeSet = millis();
isActive = true;
}
break;
case 2:
default:
// Error, or the force-off state
digitalWrite(RLY_SET1, LOW); // Turn off the elements
digitalWrite(RLY_SET2, LOW);
isActive = false;
break;
}
}
void ProcessNameChange() {
char xName[CFG_NAMESIZE];
fauxmo.getDeviceName(0, xName, CFG_NAMESIZE);
if (0 != strcmp(wifiConfig.getName().c_str(), xName)) {
fauxmo.renameDevice(0, wifiConfig.getName().c_str());
}
}
void ProcessSWUpdate() {
static unsigned long lastCheck;
unsigned long nowCheck = millis();
if ((nowCheck - lastCheck) > (UPDATE_INTERVAL)) {
lastCheck = nowCheck;
updateCheck = true;
}
if (updateCheck) {
WiFiClient wifiClient;
swUpdateInProcess = true;
Serial.printf("SW Update start '%s'...\n", wifiConfig.getURL().c_str());
t_httpUpdate_return swRet = Updater.update(wifiClient, wifiConfig.getURL(), MyVer);
switch (swRet) {
default:
case HTTP_UPDATE_FAILED:
Serial.printf("SW Update - failed.\n");
Serial.printf("Error: %s\n", Updater.getLastErrorString().c_str());
delay(100);
ESP.restart();
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.printf("SW Update - no updates.\n");
break;
case HTTP_UPDATE_OK:
Serial.printf("SW Update - update ok.\n");
break;
}
swUpdateInProcess = false;
updateCheck = false;
Serial.printf("SW Update - process end.\n");
}
}
void ProcessConsole() {
if (Serial.available()) {
int ch = Serial.read();
Serial.printf("Serial.available() => %d\n", ch);
switch (ch) {
case '0':
iRawSum = 10;
break;
case '1':
iRawSum = 1000;
break;
case 'd':
DebugValue = !DebugValue;
break;
case 'u':
updateCheck = true;
break;
case '\x0D': // Ignore <cr>
break;
case '?':
default:
DebugValue = false;
Serial.printf("Commands:\n");
Serial.printf(" 0|1 Off or On (by forcing rawSum\n");
Serial.printf(" d Debug toggle\n");
Serial.printf(" u update check\n");
break;
}
}
static unsigned long last = millis();
if (millis() - last > 5000) {
static uint32_t refFreeHeap;
uint32_t freeHeap = ESP.getFreeHeap();
last = millis();
if (freeHeap != refFreeHeap)
Serial.printf("[MAIN] Free heap: %d bytes\n", ESP.getFreeHeap());
refFreeHeap = freeHeap;
}
}
void ProcessAutoOff(bool init) {
static unsigned long lastCheck;
unsigned long nowCheck = millis();
if (init)
lastCheck = nowCheck;
if (autoOffTimer && ((nowCheck - lastCheck) >= 1000)) {
lastCheck += 1000;
--autoOffTimer;
SetLED(LED_ON, autoOffTimer & 1); // During auto-Off, blink slowly...
if (autoOffTimer == 0) {
Serial.printf("AutoOff time remaining 0 sec. Off Now.\n");
SetCircuit(CMD_Off);
}
else {
Serial.printf("AutoOff time remaining %d sec\n", autoOffTimer);
}
}
}
void HWIOInit() {
// User push-buttons
pinMode(SW_TOGGLE, INPUT);
pinMode(SW_RESET, INPUT);
// Turn off relay drivers
pinMode(RLY_SET1, OUTPUT);
digitalWrite(RLY_SET1, 0);
pinMode(RLY_SET2, OUTPUT);
digitalWrite(RLY_SET2, 0);
// Turn off user LEDs
pinMode(LED_ON, OUTPUT);
digitalWrite(LED_ON, 0);
pinMode(LED_WIFI, OUTPUT);
digitalWrite(LED_WIFI, 0);
void setup() {
Serial.begin(115200);
Serial.printf("\n");
Serial.printf("\n******************************************************************\n");
Serial.printf(" %s Web Server - Build " __DATE__ " " __TIME__ "\n", AP_NAME.c_str());
Serial.printf(" Version %s\n", AP_VERS.c_str());
Serial.printf(" Copyright (c) 2021 by Smartware Computing, all rights reserved.\n");
Serial.printf("******************************************************************\n");
wifiConfig.load();
}
void setup(void) {
HWIOInit();
ResetMonitor(true); /// Initialize the reset switch monitor for long press
Serial.begin(115200);
Serial.printf("\n******************************************************************\n");
Serial.printf(" GrowController Web Server - Build " __DATE__ " " __TIME__ "\n");
Serial.printf(" Version %s\n", MyVer.c_str());
Serial.printf(" Copyright (c) 2018 by Smartware Computing, all rights reserved.\n");
Serial.printf("******************************************************************\n");
void loop() {
//
// Process WiFi State Changes
//
static WiFiConnectState lastState = WFC_Idle;
WiFiConnectState currState = WiFiStateHandler();
if (lastState != currState) {
lastState = currState;
switch (currState) { // On change to this state
default:
break;
case WFC_HostingAP:
case WFC_JoinedAP:
StartWebServer();
break;
}
} else {
switch (currState) {
default:
break;
case WFC_HostingAP:
case WFC_JoinedAP:
server.handleClient();
break;
}
}
GetMac();
AP_SSID += "-";
AP_SSID += clientMac;
wifiConfig.load();
String name = wifiConfig.getName();
String ssid = wifiConfig.getSSID();
String pass = wifiConfig.getPassword();
if (ssid == "" || pass == "")
wifiConState = WFC_CreateAP;
else
wifiConState = WFC_ConnectToAP;
#if 0
if (MDNS.begin("esp")) { // clientMac.c_str()
//MDNS.addService("switch", "tcp", 80);
//MDNS.addServiceTxt("switch", "tcp", "switchkey", "SWITCHVALUE");
Serial.printf("MDNS responder started.\n");
}
#endif
StartWebServer();
#if 1
fauxmo.addDevice(name.c_str());
fauxmo.enable(true);
fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state) {
Serial.printf("[MAIN] Device #%d (%s) state command: %s\n", device_id, device_name, state ? "ON" : "OFF");
if ((state && !CurrStatus)
|| (!state && CurrStatus)) {
SetCircuit(RelayState ? CMD_Off : CMD_On);
}
});
fauxmo.onGetState([](unsigned char device_id, const char * device_name) {
(void) device_id;
(void) device_name;
return CurrStatus; // GetCircuitStatus(); // whatever the state of the device is
});
#endif
//
//
//
simulation();
// @todo delay(1);
}
void loop(void) {
ResetMonitor(); // Monitor for long press to factory reset
WiFiStateHandler(); // start/connect as AP or Station
ProcessSWUpdate(); // query the server for fresh SW
fauxmo.handle(); // WEMO interface
ProcessNameChange(); // Update fauxmo if the name changes
ProcessCurrentSense(); // Get status by measuring current
ProcessToggleSw(); // Monitor for user pressing toggle
DriveRelay(); // Do what the relays need, if anything
ProcessConsole();
ProcessAutoOff(); // If auto-off is enabled...
}
// ###########################################################################
void WiFiStateHandler() {
static unsigned long timeStateChange = 0;
static unsigned long timeLEDControl;
unsigned long timeLEDCycle;
String ssid = wifiConfig.getSSID();
String pass = wifiConfig.getPassword();
IPAddress myIP;
timeLEDCycle = millis() - timeLEDControl;
if (timeLEDCycle >= LED_PERIOD__MS) {
timeLEDControl = millis();
timeLEDCycle = 0;
}
switch (wifiConState) {
case WFC_ConnectToAP:
isStationMode = true;
WiFi.mode(WIFI_STA);
ssid = wifiConfig.getSSID();
pass = wifiConfig.getPassword();
WiFi.begin(ssid.c_str(), pass.c_str());
timeStateChange = millis();
timeLEDControl = timeStateChange;
wifiConState = WFC_JoiningAP;
break;
case WFC_JoiningAP:
if (timeLEDCycle <= LED_JOINING_MS)
SetLED(LED_WIFI, 1);
else
SetLED(LED_WIFI, 0);
if (WiFi.status() == WL_CONNECTED) {
myIP = WiFi.localIP();
Serial.printf("IP Address: %s\n", myIP.toString().c_str());
timeStateChange = millis();
StartWebServer();
wifiConState = WFC_JoinedAP;
} else if (millis() - timeStateChange > 30000) {
timeStateChange = millis();
wifiConState = WFC_CreateAP; // failed for 30 sec, now what. retry or CreateAP?
}
break;
case WFC_CreateAP:
if (timeLEDCycle <= LED_APMODE__MS)
SetLED(LED_WIFI, 1);
else
SetLED(LED_WIFI, 0);
isStationMode = false;
Serial.printf("Starting Access Point %s\n", AP_SSID.c_str());
WiFi.softAP(AP_SSID.c_str());
myIP = WiFi.softAPIP();
Serial.printf("IP Address: %s\n", myIP.toString().c_str());
dnsServer.start(DNS_PORT, "*", apIP);
timeStateChange = millis();
StartWebServer();
wifiConState = WFC_HostingAP;
break;
case WFC_JoinedAP:
if (timeLEDCycle <= LED_JOINED__MS)
SetLED(LED_WIFI, 1);
else
SetLED(LED_WIFI, 0);
server.handleClient();
break;
case WFC_HostingAP:
if (timeLEDCycle <= LED_APMODE__MS)
SetLED(LED_WIFI, 1);
else
SetLED(LED_WIFI, 0);
server.handleClient();
dnsServer.processNextRequest();
break;
}
}
bool GetCircuitStatus() {
return CurrStatus;
}
void SetCircuit(CircuitCmd_T newState) {
if (swUpdateInProcess)
return;
switch (newState) {
case CMD_Off:
if (GetCircuitStatus()) {
RelayState = !RelayState;
DriveRelay(RelayState);
}
break;
case CMD_On:
if (!GetCircuitStatus()) {
RelayState = !RelayState;
DriveRelay(RelayState);
}
break;
case CMD_Toggle:
RelayState = !RelayState;
DriveRelay(RelayState);
break;
default:
break;
}
}
void HandleCircuitOn() {
SetCircuit(CMD_On);
HandleGetState(); // Reply with current state
}
void HandleCircuitOff() {
SetCircuit(CMD_Off);
HandleGetState(); // Reply with current state
}
void HandleCircuitToggle() {
SetCircuit(CMD_Toggle);
HandleGetState(); // Reply with current state
}
// {
// "id": "5c:cf:7f:c0:52:82",
// "name": "3-Way Switch",
// "state": 0,
// "sense": 56,
// "ip": "192.168.1.23",
// "rssi": -63,
// "countdown": "3:45",
// "uptime": "0:11:45",
// "wifimode": "station"|"ap",
// }
//
void HandleGetState() {
int day, hr, min, sec;
char _upTime[15]; // 0000.00:00:00\0 + 1 spare
char _timeout[10]; // 00:00:00\0 + 1 spare
sec = millis() / 1000;
min = sec / 60;
hr = min / 60;
day = hr / 24;
if (day)
snprintf(_upTime, sizeof(_upTime), "%dd %d:%02d:%02d", day, hr % 24, min % 60, sec % 60);
else if (hr)
snprintf(_upTime, sizeof(_upTime), "%d:%02d:%02d", hr, min % 60, sec % 60);
else
snprintf(_upTime, sizeof(_upTime), "%02d:%02d", min % 60, sec % 60);
sec = autoOffTimer;
min = sec / 60;
hr = min / 60;
if (hr)
snprintf(_timeout, sizeof(_timeout), "%d:%02d:%02d", hr, min % 60, sec % 60);
else
snprintf(_timeout, sizeof(_timeout), "%d:%02d", min, sec % 60);
GetMac();
String modeText = (isStationMode) ? "Station" : "Access Point";
String message = "{ \"id\": \"" + String(clientMac) + "\", ";
message += "\"name\": \"" + wifiConfig.getName() + "\", ";
message += "\"version\": \"" + MyVer + "\", ";
message += "\"state\": " + String(CurrStatus) + ", ";
message += "\"raw\": " + String(iRaw) + ", ";
message += "\"sense\": " + String(iRawSum / AVG_RATIO) + ", ";
message += "\"ip\": \""
+ String(WiFi.localIP()[0])
+ "." + String(WiFi.localIP()[1])
+ "." + String(WiFi.localIP()[2])
+ "." + String(WiFi.localIP()[3])
+ "\", ";
message += "\"rssi\": " + String(WiFi.RSSI()) + ", ";
message += "\"countdown\": \"" + String(_timeout) + "\", ";
message += "\"uptime\": \"" + String(_upTime) + "\", ";
message += "\"wifimode\": \"" + modeText + "\", ";
message += "\"toggle\": " + String(!digitalRead(SW_TOGGLE)) + ", ";
message += "\"reset\": " + String(!digitalRead(SW_RESET));
message += " }";
if (DebugValue)
Serial.println(message + "\0");
server.sendHeader("Access-Control-Allow-Origin", String("*"), true);
server.send(200, "text/plain", message);
}
// Prototypes:
// const char Button_css[]
// const char favicon_ico[]
// const char Green1x1_png[]
// const char index_htm[]
// const char index_js[]
// const char rssi_htm[]
// const char rssi_js[]
void HandleSWUpdateCheck() {
updateCheck = true;
HandleAPConfigPage();
}
void HandleButton_css() {
server.sendHeader("Access-Control-Allow-Origin", String("*"), true);
server.send_P(200, "text/plain", Button_css);
}
void HandleIndex_js() {
server.sendHeader("Access-Control-Allow-Origin", String("*"), true);
server.send_P(200, "text/plain", index_js);
}
void HandleAbout_htm() {
server.sendHeader("Access-Control-Allow-Origin", String("*"), true);
server.send_P(200, "text/html", about_htm);
}
void HandleAbout_js() {
server.sendHeader("Access-Control-Allow-Origin", String("*"), true);
server.send_P(200, "text/plain", about_js);
}
void HandleMyIP_js() {
server.sendHeader("Access-Control-Allow-Origin", String("*"), true);
String message = "var mySite = 'http://";
message += String(WiFi.localIP()[0]);
message += "." + String(WiFi.localIP()[1]);
message += "." + String(WiFi.localIP()[2]);
message += "." + String(WiFi.localIP()[3]);
message += "';\n";
server.send(200, "text/plain", message);
}
void StartWebServer() {
// path /firmware
//httpUpdater.setup(&server, update_path, update_username, update_password);
server.on("/", HandleRootPage);
server.on("/myip.js", HandleMyIP_js);
server.on("/button.css", HandleButton_css);
server.on("/index.js", HandleIndex_js);
server.on("/about", HandleAbout_htm);
server.on("/about.js", HandleAbout_js);
server.on("/favicon.ico", HandleFavIcon);
server.on("/PlantModel.png", HandlePlantModel);
server.on("/Heater.png", HandleHeater);
server.on("/Water.png", HandleWater);
server.on("/config", HandleAPConfigPage);
server.on("/swupdatecheck", HandleSWUpdateCheck);
server.on("/scan", HandleAPScan);
server.on("/green1x1.png", HandleGreen1x1);
server.on("/rssi", HandleRSSIPage);
server.on("/rssi.js", HandleRSSI_JS);
server.on("/curr", HandleCurrPage);
server.on("/curr.js", HandleCurr_JS);
server.on("/on", HandleCircuitOn);
server.on("/off", HandleCircuitOff);
server.on("/toggle", HandleCircuitToggle);
server.on("/state", HandleGetState);
server.on("/icon.png", HandleIcon);
server.on("/Open.png", HandleOpenDoor);
server.onNotFound(HandleNotFound);
server.begin();
Serial.println("HTTP server started");
// path /firmware
Serial.println("HTTP server starting ...");
//httpUpdater.setup(&server, update_path, update_username, update_password);
server.on("/", HandleRootPage);
server.on("/config", HandleAPConfigPage);
server.on("/myip.js", HandleMyIP_js);
server.on("/nav.js", HandleNav_js);
server.on("/plantmodel.png", HandlePlantModel);
server.on("/plantmodel.css", HandlePlantModel_css);
server.on("/button.css", HandleButton_css);
server.on("/index.js", HandleIndex_js);
server.on("/about.htm", HandleAbout_htm);
server.on("/about.js", HandleAbout_js);
server.on("/favicon.ico", HandleFavIcon);
server.on("/soilheater_on.png", HandleHeaterOn);
server.on("/soilheater_off.png", HandleHeaterOff);
server.on("/thermometer.png", HandleThermometer);
server.on("/soilmoisture.png", HandleSoilMoisture);
server.on("/pointer.png", HandlePointer);
server.on("/water.png", HandleWater);
server.on("/green1x1.png", HandleGreen1x1);
server.on("/rssi.htm", HandleRSSIPage);
server.on("/rssi.js", HandleRSSI_js);
server.on("/curr.htm", HandleCurrPage);
server.on("/curr.js", HandleCurr_js);
server.on("/icon.png", HandleIcon);
server.on("/open.png", HandleOpenDoor);
server.on("/swupdatecheck", HandleSWUpdateCheck);
server.on("/scan", HandleAPScan);
//server.on("/on", HandleCircuitOn);
//server.on("/off", HandleCircuitOff);
//server.on("/toggle", HandleCircuitToggle);
server.on("/state", HandleGetState);
server.on("/description.xml", HTTP_GET, []() {
Serial.printf("description.xml handler.\n");
SSDP.schema(server.client());
});
server.onNotFound(HandleNotFound);
server.begin();
Serial.println("HTTP server started.");
//
// SSDP Startup
//
Serial.printf("SSDP server starting ...\n");
SSDP.setSchemaURL("description.xml");
SSDP.setHTTPPort(80);
SSDP.setName(wifiConfig.getName().c_str()); // "Philips hue clone");
SSDP.setSerialNumber("001788102201");
SSDP.setURL("/"); // Root Page
SSDP.setModelName(AP_NAME.c_str()); // "Philips hue bridge 2012");
SSDP.setModelNumber("929000226503");
SSDP.setModelURL("https://www.smart-family.net/GrowController");
SSDP.setManufacturer("Smartware Computing");
SSDP.setManufacturerURL("https://www.smart-family.net");
SSDP.setDeviceType("upnp:rootdevice");
SSDP.begin();
Serial.println("SSDP server started.");
}
void HandleNotFound() {
Serial.printf("not found: %s\n", server.uri().c_str());
const DirEntry *de = Directory;
boolean found = false;
while (*de->Filename) {
if (0 == strcmp(de->Filename, server.uri().c_str())) {
Serial.printf("send %s\n", de->Filename);
server.send_P(200, de->Filetype, de->Filedata, de->Filesize);
found = true;
break;
} else {
de++;
}
}
if (!found) {
Serial.printf("!found - redirect to home\n");
server.sendHeader("Location", String("/"), true);
server.send(302, "text/plain", "Not supported. Heading for home.");
}
}
void GetMac() {
unsigned char mac[6];
WiFi.macAddress(mac);
clientMac = macToStr(mac);
}
String macToStr(const uint8_t * mac) {
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5)
result += ':';
}
return result;
void FactoryReset(bool forceRestart) {
Serial.println("Factory Reset Configuration...\n");
wifiConfig.factoryReset();
wifiConfig.save();
if (forceRestart) {
Serial.println("Restart in 3 sec ...");
delay(3000);
ESP.restart();
}
}