Skip to content

Commit

Permalink
Feature: Indefinite scheduled messages and WiFi Static IP Address (#9)
Browse files Browse the repository at this point in the history
* Added functionality for making a message displayed on a schedule permanent
* Fixed issue where WiFi direct mode did not work correctly
* Fixed issue with TimeZone being set on the UI 
* Added experimental feature for setting a static IP address
* Updated build dependencies
* README updates
  • Loading branch information
JonnyBooker committed Apr 18, 2024
1 parent 4f18b07 commit 671666c
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 54 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build-esp-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ jobs:
- ./ESPMaster
libraries: |
- name: ArduinoJson
version: 7.0.3
version: 7.0.4
- name: ArduinoOTA
version: 1.0.12
version: 1.1.0
- name: ESPAsyncWebSrv
version: 1.2.7
- name: ezTime
Expand Down
1 change: 1 addition & 0 deletions ESPMaster/Classes.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
struct ScheduledMessage {
String Message;
long ScheduledDateTimeUnix;
bool ShowIndefinitely;
};

//Used as a work around for issues that linked list has with other libraries
Expand Down
56 changes: 44 additions & 12 deletions ESPMaster/ESPMaster.ino
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@
#define OTA_ENABLE true //Option to enable OTA functionality
#define UNITS_AMOUNT 10 //Amount of connected units !IMPORTANT TO BE SET CORRECTLY!
#define SERIAL_BAUDRATE 115200 //Serial debugging BAUD rate
#define WIFI_SETUP_MODE AP //Option to either direct connect to a WiFi Network or setup a AP to configure WiFi. Options: AP or DIRECT
#define WIFI_USE_DIRECT false //Option to either direct connect to a WiFi Network or setup a AP to configure WiFi. Setting to false will setup as a AP.

/*
EXPERIMENTAL: Try to use your Router when possible to set a Static IP address for your device to avoid conflicts with other devices
on your network. This will try and setup your device with a static IP address of your chosing. See below for more details.
*/
#define WIFI_STATIC_IP false

/* .--------------------------------------------------------. */
/* | ___ _ ___ __ _ | */
Expand All @@ -45,7 +51,6 @@
#define FLAP_AMOUNT 45 //Amount of Flaps in each unit
#define MIN_SPEED 1 //Min Speed
#define MAX_SPEED 12 //Max Speed
#define WEBSERVER_H //Needed in order to be compatible with WiFiManager: https://github.com/me-no-dev/ESPAsyncWebServer/issues/418#issuecomment-667976368

/* .-----------------------------------. */
/* | _ _ _ _ | */
Expand All @@ -59,7 +64,9 @@

//WiFi Setup Library if we use that mode
//Specifically put here in this order to avoid conflict with other libraries
#if WIFI_SETUP_MODE == AP
#if WIFI_USE_DIRECT == false
//Needed in order to be compatible with WiFiManager: https://github.com/me-no-dev/ESPAsyncWebServer/issues/418#issuecomment-667976368
#define WEBSERVER_H
#include <WiFiManager.h>
#endif

Expand Down Expand Up @@ -89,7 +96,7 @@
/*
Settings you can feel free to change to customise how your display works.
*/
//Used if connecting via "WIFI_SETUP_MODE" of "DIRECT" - Otherwise, leave blank
//Used if connecting via "WIFI_USE_DIRECT" of "true" - Otherwise, leave blank
const char* wifiDirectSsid = "";
const char* wifiDirectPassword = "";

Expand All @@ -108,6 +115,19 @@ const char* clockFormat = "H:i"; //Examples: H:i -> 21:19, h:ia -> 09:19PM
//How long to show a message for when a scheduled message is shown for
const int scheduledMessageDisplayTimeMillis = 7500;

#if WIFI_STATIC_IP == true
//Static IP address for your device. Try take care to not conflict with something else on your network otherwise
//it is likely to not work
IPAddress wifiDeviceStaticIp(192, 168, 1, 100);

//Your router details
IPAddress wifiRouterGateway(192, 168, 1, 1);
IPAddress wifiSubnet(255, 255, 0, 0);

//DNS Entry. Default: Google DNS
IPAddress wifiPrimaryDns(8, 8, 8, 8);
#endif

/* .------------------------------------------------------------. */
/* | ___ _ ___ _ _ _ | */
/* |/ __|_ _ __| |_ ___ _ __ / __|___| |_| |_(_)_ _ __ _ ___| */
Expand All @@ -120,7 +140,7 @@ const int scheduledMessageDisplayTimeMillis = 7500;
behave a little strange.
*/
//The current version of code to display on the UI
const char* espVersion = "2.1.0";
const char* espVersion = "2.2.0";

//All the letters on the units that we have to be displayed. You can change these if it so pleases at your own risk
const char letters[] = {' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '$', '&', '#', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '.', '-', '?', '!'};
Expand All @@ -134,6 +154,7 @@ const char* PARAM_DEVICEMODE = "deviceMode";
const char* PARAM_INPUT_TEXT = "inputText";
const char* PARAM_SCHEDULE_ENABLED = "scheduleEnabled";
const char* PARAM_SCHEDULE_DATE_TIME = "scheduledDateTimeUnix";
const char* PARAM_SCHEDULE_SHOW_INDEFINITELY = "scheduleShowIndefinitely";
const char* PARAM_COUNTDOWN_DATE = "countdownDateTimeUnix";
const char* PARAM_ID = "id";

Expand Down Expand Up @@ -165,18 +186,18 @@ String lastWrittenText = "";
String lastReceivedMessageDateTime = "";
bool alignmentUpdated = false;
bool isPendingReboot = false;
bool isPendingWifiReset = false;
bool isPendingUnitsReset = false;
bool isWifiConfigured = false;
LList<ScheduledMessage> scheduledMessages;
Timezone timezone;

//Create AsyncWebServer object on port 80
AsyncWebServer webServer(80);

//Used for creating a Access Point to allow WiFi setup
#if WIFI_SETUP_MODE == AP
#if WIFI_USE_DIRECT == false
WiFiManager wifiManager;
bool isWifiConfigured = false;
bool isPendingWifiReset = false;
#endif

//Used to denote that the system has gone into OTA mode
Expand Down Expand Up @@ -309,8 +330,8 @@ void setup() {

bool submissionError = false;

bool newMessageScheduleEnabledValue;
long newMessageScheduleDateTimeUnixValue;
bool newMessageScheduleEnabledValue, newMessageScheduleShowIndefinitely;
String newAlignmentValue, newDeviceModeValue, newFlapSpeedValue, newInputTextValue, newCountdownToDateUnixValue;

int params = request->params();
Expand Down Expand Up @@ -358,6 +379,14 @@ void setup() {
true :
false;
}

//HTTP POST Schedule Show Indefinitely
if (p->name() == PARAM_SCHEDULE_SHOW_INDEFINITELY) {
String newMessageScheduleShowIndefinitelyString = p->value().c_str();
newMessageScheduleShowIndefinitely = newMessageScheduleShowIndefinitelyString == "on" ?
true :
false;
}

//HTTP POST Schedule Seconds
if (p->name() == PARAM_SCHEDULE_DATE_TIME) {
Expand Down Expand Up @@ -423,7 +452,7 @@ void setup() {
//If its a new scheduled message, add it to the backlog and proceed, don't want to change device mode
//Else, we do want to change the device mode and clear out the input text
if (newMessageScheduleEnabledValue) {
addAndPersistScheduledMessage(newInputTextValue, newMessageScheduleDateTimeUnixValue);
addAndPersistScheduledMessage(newInputTextValue, newMessageScheduleDateTimeUnixValue, newMessageScheduleShowIndefinitely);
SerialPrintln("New Scheduled Message added");
}
else {
Expand Down Expand Up @@ -527,7 +556,7 @@ void setup() {
});
#endif

#if WIFI_SETUP_MODE == AP
#if WIFI_USE_DIRECT == false
webServer.on("/reset-wifi", HTTP_GET, [](AsyncWebServerRequest * request) {
SerialPrintln("Request to Reset WiFi Received");

Expand Down Expand Up @@ -584,6 +613,7 @@ void loop() {
return;
}

#if WIFI_USE_DIRECT == false
//Clear off the WiFi Manager Settings
if (isPendingWifiReset) {
SerialPrintln("Removing WiFi settings");
Expand All @@ -593,6 +623,7 @@ void loop() {
isPendingReboot = true;
return;
}
#endif

//Do nothing if WiFi is not configured
if (!isWifiConfigured) {
Expand Down Expand Up @@ -675,6 +706,7 @@ String getCurrentSettingValues() {

document["scheduledMessages"][scheduledMessageIndex]["scheduledDateTimeUnix"] = scheduledMessage.ScheduledDateTimeUnix;
document["scheduledMessages"][scheduledMessageIndex]["message"] = scheduledMessage.Message;
document["scheduledMessages"][scheduledMessageIndex]["showIndefinitely"] = scheduledMessage.ShowIndefinitely;
}

#if OTA_ENABLE == true
Expand All @@ -684,7 +716,7 @@ String getCurrentSettingValues() {
document["otaEnabled"] = false;
#endif

#if WIFI_SETUP_MODE == AP
#if WIFI_USE_DIRECT == false
document["wifiSettingsResettable"] = true;
#else
document["wifiSettingsResettable"] = false;
Expand Down
31 changes: 24 additions & 7 deletions ESPMaster/ServiceScheduledMessageFunctions.ino
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
//Replace/add a scheduled message and persist the result afterwards
void addAndPersistScheduledMessage(String scheduledText, long scheduledDateTimeUnix) {
addScheduledMessage(scheduledText, scheduledDateTimeUnix);
void addAndPersistScheduledMessage(String scheduledText, long scheduledDateTimeUnix, bool showIndefinitely) {
addScheduledMessage(scheduledText, scheduledDateTimeUnix, showIndefinitely);
writeScheduledMessagesToFile();
}

//Replace/add a scheduled message
void addScheduledMessage(String scheduledText, long scheduledDateTimeUnix) {
SerialPrintln("Processing New Scheduled Message: " + scheduledText);
void addScheduledMessage(String scheduledText, long scheduledDateTimeUnix, bool showIndefinitely) {
SerialPrintln("Processing New Scheduled Message");
SerialPrintln("-- Message: " + scheduledText);
SerialPrint("-- Unix: ");
SerialPrintln(scheduledDateTimeUnix);
SerialPrint("-- Show Indefinitely: ");
SerialPrintln(showIndefinitely ? "Yes" : "No");

//Find the existing scheduled message and update it if one exists
for(int scheduledMessageIndex = 0; scheduledMessageIndex < scheduledMessages.size(); scheduledMessageIndex++) {
Expand All @@ -22,7 +27,7 @@ void addScheduledMessage(String scheduledText, long scheduledDateTimeUnix) {
//Add the new scheduled message with the new value
if (scheduledDateTimeUnix > timezone.now()) {
SerialPrintln("Adding new Scheduled Message");
scheduledMessages.add({scheduledText, scheduledDateTimeUnix});
scheduledMessages.add({scheduledText, scheduledDateTimeUnix, showIndefinitely});
}
else {
SerialPrintln("Not adding Scheduled Message as it is in the past");
Expand Down Expand Up @@ -58,7 +63,17 @@ void checkScheduledMessages() {

if (currentTimeUnix > scheduledMessage.ScheduledDateTimeUnix) {
SerialPrintln("Scheduled Message due to be shown: " + scheduledMessage.Message);
showText(scheduledMessage.Message, scheduledMessageDisplayTimeMillis);
SerialPrint("Scheduled Message to be Shown Indefinitely: ");
SerialPrintln(scheduledMessage.ShowIndefinitely ? "Yes" : "No");

if (scheduledMessage.ShowIndefinitely) {
deviceMode = DEVICE_MODE_TEXT;
inputText = scheduledMessage.Message;
showText(scheduledMessage.Message);
}
else {
showText(scheduledMessage.Message, scheduledMessageDisplayTimeMillis);
}

scheduledMessages.remove(scheduledMessageIndex);
writeScheduledMessagesToFile();
Expand All @@ -80,8 +95,9 @@ void readScheduledMessagesFromJson(String scheduledMessagesJson) {
for (JsonVariant value : jsonDocument.as<JsonArray>()) {
long scheduledDateTimeUnix = value["scheduledDateTimeUnix"];
String message = value["message"];
bool showIndefinitely = value["showIndefinitely"];

addScheduledMessage(message, scheduledDateTimeUnix);
addScheduledMessage(message, scheduledDateTimeUnix, showIndefinitely);
addedScheduledMessageCount++;
}

Expand Down Expand Up @@ -112,6 +128,7 @@ void writeScheduledMessagesToFile() {

scheduledMessagesDocument[scheduledMessageIndex]["scheduledDateTimeUnix"] = scheduledMessage.ScheduledDateTimeUnix;
scheduledMessagesDocument[scheduledMessageIndex]["message"] = scheduledMessage.Message;
scheduledMessagesDocument[scheduledMessageIndex]["showIndefinitely"] = scheduledMessage.ShowIndefinitely;
}

String scheduledMessagesJson;
Expand Down
18 changes: 16 additions & 2 deletions ESPMaster/ServiceWifiFunctions.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ void initWiFi() {

WiFi.mode(WIFI_STA);

#if WIFI_SETUP_MODE == AP
#if WIFI_USE_DIRECT == false
SerialPrintln("Setting up WiFi AP Setup Mode");

#if WIFI_STATIC_IP == true
wifiManager.setSTAStaticIPConfig(wifiDeviceStaticIp, wifiRouterGateway, wifiSubnet, wifiPrimaryDns);
SerialPrintln("WiFi Static IP Configured");
#endif

wifiManager.setTitle("Split-Flap Setup");
wifiManager.setHostname("Split-Flap");
wifiManager.setDarkMode(true);
Expand Down Expand Up @@ -44,9 +49,18 @@ void initWiFi() {
#else
SerialPrintln("Setting up WiFi Direct");

if (ssid != "" && password != "") {
if (wifiDirectSsid != "" && wifiDirectPassword != "") {
int maxAttemptsCount = 0;

#if WIFI_STATIC_IP == true
if (WiFi.config(wifiDeviceStaticIp, wifiRouterGateway, wifiSubnet, wifiPrimaryDns)) {
SerialPrintln("WiFi Static IP Configuration Success");
}
else {
SerialPrintln("WiFi Static IP Configuration could not take place");
}
#endif

WiFi.begin(wifiDirectSsid, wifiDirectPassword);
SerialPrint("Connecting");

Expand Down
15 changes: 11 additions & 4 deletions ESPMaster/data/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,18 @@ <h4 class="float-right" style="text-align: right;">
</p>

<p>
<label for="scheduledDateTime">Schedule Message?</label>
<label for="inputCheckboxScheduleEnabled">Schedule Message?</label>
<input type="checkbox" id="inputCheckboxScheduleEnabled" name="scheduleEnabled" onchange="showHideScheduledMessageInput()" />
<br>
<input type="datetime-local" class="hidden" id="inputScheduledDateTime" name="scheduleDateTime">
<input type="hidden" id="inputHiddenScheduledDateTimeUnix" name="scheduledDateTimeUnix" value="0" />
<div id="divScheduleOptions" class="hidden">
<p>
<label for="scheduledDateTime">Show Indefinitely?</label>
<input type="checkbox" id="inputCheckboxShowIndefinitely" name="scheduleShowIndefinitely" />
</p>
<p>
<input type="datetime-local" id="inputScheduledDateTime" name="scheduleDateTime">
<input type="hidden" id="inputHiddenScheduledDateTimeUnix" name="scheduledDateTimeUnix" value="0" />
</p>
</div>
</p>
</div>

Expand Down
Loading

0 comments on commit 671666c

Please sign in to comment.