diff --git a/.github/workflows/build-esp-master.yml b/.github/workflows/build-esp-master.yml index dd4959c..f1c42fb 100644 --- a/.github/workflows/build-esp-master.yml +++ b/.github/workflows/build-esp-master.yml @@ -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 diff --git a/ESPMaster/Classes.h b/ESPMaster/Classes.h index 506621a..fb31d74 100644 --- a/ESPMaster/Classes.h +++ b/ESPMaster/Classes.h @@ -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 diff --git a/ESPMaster/ESPMaster.ino b/ESPMaster/ESPMaster.ino index 2debdab..048179e 100644 --- a/ESPMaster/ESPMaster.ino +++ b/ESPMaster/ESPMaster.ino @@ -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 /* .--------------------------------------------------------. */ /* | ___ _ ___ __ _ | */ @@ -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 /* .-----------------------------------. */ /* | _ _ _ _ | */ @@ -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 #endif @@ -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 = ""; @@ -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 + /* .------------------------------------------------------------. */ /* | ___ _ ___ _ _ _ | */ /* |/ __|_ _ __| |_ ___ _ __ / __|___| |_| |_(_)_ _ __ _ ___| */ @@ -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', ':', '.', '-', '?', '!'}; @@ -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"; @@ -165,8 +186,8 @@ String lastWrittenText = ""; String lastReceivedMessageDateTime = ""; bool alignmentUpdated = false; bool isPendingReboot = false; -bool isPendingWifiReset = false; bool isPendingUnitsReset = false; +bool isWifiConfigured = false; LList scheduledMessages; Timezone timezone; @@ -174,9 +195,9 @@ Timezone timezone; 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 @@ -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(); @@ -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) { @@ -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 { @@ -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"); @@ -584,6 +613,7 @@ void loop() { return; } +#if WIFI_USE_DIRECT == false //Clear off the WiFi Manager Settings if (isPendingWifiReset) { SerialPrintln("Removing WiFi settings"); @@ -593,6 +623,7 @@ void loop() { isPendingReboot = true; return; } +#endif //Do nothing if WiFi is not configured if (!isWifiConfigured) { @@ -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 @@ -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; diff --git a/ESPMaster/ServiceScheduledMessageFunctions.ino b/ESPMaster/ServiceScheduledMessageFunctions.ino index f11e9cd..fdfcac8 100644 --- a/ESPMaster/ServiceScheduledMessageFunctions.ino +++ b/ESPMaster/ServiceScheduledMessageFunctions.ino @@ -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++) { @@ -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"); @@ -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(); @@ -80,8 +95,9 @@ void readScheduledMessagesFromJson(String scheduledMessagesJson) { for (JsonVariant value : jsonDocument.as()) { long scheduledDateTimeUnix = value["scheduledDateTimeUnix"]; String message = value["message"]; + bool showIndefinitely = value["showIndefinitely"]; - addScheduledMessage(message, scheduledDateTimeUnix); + addScheduledMessage(message, scheduledDateTimeUnix, showIndefinitely); addedScheduledMessageCount++; } @@ -112,6 +128,7 @@ void writeScheduledMessagesToFile() { scheduledMessagesDocument[scheduledMessageIndex]["scheduledDateTimeUnix"] = scheduledMessage.ScheduledDateTimeUnix; scheduledMessagesDocument[scheduledMessageIndex]["message"] = scheduledMessage.Message; + scheduledMessagesDocument[scheduledMessageIndex]["showIndefinitely"] = scheduledMessage.ShowIndefinitely; } String scheduledMessagesJson; diff --git a/ESPMaster/ServiceWifiFunctions.ino b/ESPMaster/ServiceWifiFunctions.ino index 7bf875c..fcab7be 100644 --- a/ESPMaster/ServiceWifiFunctions.ino +++ b/ESPMaster/ServiceWifiFunctions.ino @@ -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); @@ -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"); diff --git a/ESPMaster/data/index.html b/ESPMaster/data/index.html index 6019e0e..ac00faf 100644 --- a/ESPMaster/data/index.html +++ b/ESPMaster/data/index.html @@ -95,11 +95,18 @@

- + -
- - +

diff --git a/ESPMaster/data/script.js b/ESPMaster/data/script.js index 7535073..f43151a 100644 --- a/ESPMaster/data/script.js +++ b/ESPMaster/data/script.js @@ -88,7 +88,7 @@ function loadPage() { //Set date time fields to be a minimum of todays date/time add 1 minute var tzOffset = timezoneOffset * 60000; document.querySelectorAll('input[type="datetime-local"]').forEach((dateTimeElement) => { - var currentDateTime = (new Date(Date.now() - tzOffset + 60000)).toISOString().slice(0, -8); + var currentDateTime = convertDateToString((new Date(Date.now() - tzOffset + 60000))); dateTimeElement.value = dateTimeElement.min = currentDateTime; }); @@ -105,7 +105,8 @@ function loadPage() { showScheduledMessages([ { "scheduledDateTimeUnix": 1690134480, - "message": "Test Message 1" + "message": "Test Message 1", + "showIndefinitely": false }, ]); @@ -285,20 +286,31 @@ function setCountdownDate(dateUnix) { if (dateUnix !== 0) { var countdownDate = new Date(dateUnix * 1000); if (countdownDate >= currentDate) { - currentCountdownDate.value = countdownDate.toISOString().slice(0, 10); + currentCountdownDate.value = convertDateToString(countdownDate); if (countdownDate - currentDate < 24000) { - currentCountdownDate.min = nextDayDate.toISOString().slice(0, 10); + currentCountdownDate.min = convertDateToString(nextDayDate); return; } } } else { //Set date fields to be a minimum of tomorrows date - currentCountdownDate.value = nextDayDate.toISOString().slice(0, 10); + currentCountdownDate.value = convertDateToString(nextDayDate); } - currentCountdownDate.min = nextDayDate.toISOString().slice(0, 10); + currentCountdownDate.min = convertDateToString(nextDayDate); +} + +function convertDateToString(dateTime) { + const year = dateTime.getFullYear(); + const month = String(dateTime.getMonth() + 1).padStart(2, '0'); + const day = String(dateTime.getDate()).padStart(2, '0'); + + const hours = String(dateTime.getHours()).padStart(2, '0'); + const minutes = String(dateTime.getMinutes()).padStart(2, '0'); + + return `${year}-${month}-${day}T${hours}:${minutes}`; } //Sets the last received post message to the server @@ -309,14 +321,14 @@ function setLastReceivedMessage(time) { //Used for scheduling messages function showHideScheduledMessageInput() { - var dateTimeElement = document.getElementById("inputScheduledDateTime"); + var scheduleOptionsElement = document.getElementById("divScheduleOptions"); var checkboxScheduled = document.getElementById("inputCheckboxScheduleEnabled"); if (checkboxScheduled.checked) { - dateTimeElement.classList.remove("hidden") + scheduleOptionsElement.classList.remove("hidden") } else { - dateTimeElement.classList.add("hidden") + scheduleOptionsElement.classList.add("hidden") } } @@ -353,11 +365,15 @@ function showScheduledMessages(scheduledMessages) { var timeElement = document.createElement("div"); timeElement.className = "time"; timeElement.innerText = new Date((scheduledMessage.scheduledDateTimeUnix * 1000) + (timezoneOffset * 60000)).toString().slice(0, -34); + + //Create a element to show the indefinite...ness... + var message = `Message: ${scheduledMessage.message.trim() == "" ? "" : scheduledMessage.message}` + var isIndefinitely = `Shown Indefinitely: ${scheduledMessage.showIndefinitely ? "Yes" : "No"}`; //Create a element to show the text var textElement = document.createElement("div"); textElement.className = "text"; - textElement.innerText = scheduledMessage.message.trim() == "" ? "" : scheduledMessage.message; + textElement.innerHTML = `${message}
${isIndefinitely}`; //Create a remove button var actionElement = document.createElement("div"); diff --git a/ESPMaster/data/style.css b/ESPMaster/data/style.css index 0aec1d4..b9b7c32 100644 --- a/ESPMaster/data/style.css +++ b/ESPMaster/data/style.css @@ -223,6 +223,7 @@ input[type=datetime-local] { align-items: center; justify-content: center; } + .message .text { text-align: left; padding: 5px; @@ -248,6 +249,9 @@ input[type=datetime-local] { font-size: 16px; border-radius: 4px; transition-duration: 0.4s; + justify-content: center; + align-items: center; + display: flex; } .message .action .remove-button:hover { diff --git a/README.md b/README.md index bf5c54e..07a471c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Split-Flap + [![Build ESP Master Sketch](https://github.com/JonnyBooker/split-flap/actions/workflows/build-esp-master.yml/badge.svg)](https://github.com/JonnyBooker/split-flap/actions/workflows/build-esp-master.yml) [![Build EEPROM Write Sketch](https://github.com/JonnyBooker/split-flap/actions/workflows/build-eeprom-write.yml/badge.svg)](https://github.com/JonnyBooker/split-flap/actions/workflows/build-eeprom-write.yml) [![Build Arduino Unit Sketch](https://github.com/JonnyBooker/split-flap/actions/workflows/build-unit.yml/badge.svg)](https://github.com/JonnyBooker/split-flap/actions/workflows/build-unit.yml) ![Split Flap Display](./Images/Split-Flap.jpg) @@ -6,6 +7,7 @@ This project has been forked from the brilliant [Split Flap Project](https://github.com/Dave19171/split-flap) by [David Königsmann](https://github.com/Dave19171). None of this would have been possible without the great foundations that have been put in place. This project has built on the original project to add extra features such as: + - Message Splittng - If a message is longer then the number of units there are, the message will be split up and displayed in sequence with a delay between each message - Also messages can be split up by adding a `\n` @@ -14,6 +16,7 @@ This project has built on the original project to add extra features such as: - Added ability to setup WiFi connection on device - The device will set itself up as a Access Point (AP) on first start. You will be able to connect to this network and a web portal will be provided where you can setup the WiFi network you want to connect to - If the device was to lose connection, it should retry and if all else fails, it will open up the web portal again to change the WiFi settings if necessary + - Option to be able use direct mode is also possible as previously implemented - Reworked UI - Can see messages scheduled to be displayed and option to remove them - Loading indicators @@ -25,12 +28,16 @@ This project has built on the original project to add extra features such as: - How many characters/lines are in the textbox for text - Add newline button (as typing `\n` is a pain on a mobile keyboard) - Message Scheduling - - Ability to send a message and display it at a later date. If the clock was in another mode such as `Clock` mode, it will show the message for a duration, then return to that mode + - Ability to send a message and display it at a later date. + - Options for when a scheduled message being shown + - If the clock was in another mode, such as `Clock` mode, it will show the message for a duration (changable via updating `scheduledMessageDisplayTimeMillis` in `ESPMaster.ino`), then return to that mode afterwards + - A checkbox on the UI is presented ("Show Indefinitely") that when checked, will show a message and leave it on the display - Arduino OTA - Over the Air updates to the display - Updated `README.md` to add scenarios of problems encountered Also the code has been refactored to try facilitate easier development: + - Changed serial prints to one central location so don't have to declare serial enable checks when a new one is required - Renamed files and functions - Ping endpoint @@ -39,28 +46,33 @@ Also the code has been refactored to try facilitate easier development: 3D-files here on [Printables](https://www.prusaprinters.org/prints/69464-split-flap-display)! ## General + The display's electronics use 1 x ESP01 (ESP8266) as the main hub and up to 16 Arduinos as receivers. The ESP handles the web interface and communicates to the units via I2C. Each unit is resposible for setting the zero position of the drum on startup and displaying any letter the main hub send its way. Assemble everything according to the instruction manual which you can find on [GitHub](./Instructions/SplitFlapInstructions.pdf). ### PCB -Gerber files are in the `PCB` folder. These are the scehematics for the PCB boards and say, what is needed and where. You need one per unit. Populate components according to the [instruction manual](./Instructions/SplitFlapInstructions.pdf). + +Gerber files are in the `PCB` folder. These are the scehematics for the PCB boards and say, what is needed and where. You need one per unit. Populate components according to the [instruction manual](./Instructions/SplitFlapInstructions.pdf). Options to potentially get boards created for you: + - [PCB Way](https://www.pcbway.com/) - [JLC PCB](https://jlcpcb.com/) > Note: Services are offered by these companies to assembly the boards for you. There are surface mounted components to these devices that you might not be able to do yourself like small resistors for instance, which must be flow soldered. It could be worth having the company do this aspect for you. ### Unit + Each split-flap unit consists of an Arduino Nano mounted on a custom PCB. It controls a 28BYJ-48 stepper motor via a ULN2003 driver chip. The drum with the flaps is homed with a KY003 hall sensor and a magnet mounted to the drum. -Upload the Arduino sketch `Unit.ino` in the unit folder to each unit's arduino nano. Before that set the offset with the `EEPROM_Write_Offset.ino` sketch. +Upload the Arduino sketch `Unit.ino` in the unit folder to each unit's arduino nano. Before that set the offset with the `EEPROM_Write_Offset.ino` sketch. Inside `Unit.ino`, there is a setting for testing the units so that a few letters are cycled through to ensure what is shown is what you expect. At the top of the file once you have opened the project, you will find a line that is commented out: + ```c++ #define SERIAL_ENABLE // uncomment for serial debug communication -#define TEST_ENABLE // uncomment for test mode where the unit will cycle a series of test letters. +#define TEST_ENABLE // uncomment for test mode where the unit will cycle a series of test letters. ``` > Note: If you experience any problems uploading the unit sketch, you may have to change your `Processor` to use the old bootloader, called `ATmega328p (Old Bootloader)`. @@ -68,24 +80,29 @@ Inside `Unit.ino`, there is a setting for testing the units so that a few letter Remove the comment characters to help with your testing for the next step of Setting the Zero Position Offset. #### Set Zero Position Offset + The zero position (or blank flaps position in this case) is attained by driving the stepper to the hall sensor and step a few steps forward. This offset is individual to every unit and needs to be saved to the arduino nano's EEPROM. A simple sketch has been written to set the offset. Upload the `EEPROM_Write_Offset.ino` sketch and open the serial monitor with 115200 baudrate. It will tell you the current offset and you can enter a new offset. It should be around 100 but yours may vary. You may need to upload the `Unit.ino` sketch with the `TEST_ENABLE` flag uncommented and see if the offset is correct. Repeat until the blank flap is showing every time the unit homes. #### Set Unit Address + Every units address is set by a DIP switch. They need to be set ascending from zero in binary. This is how my 10 units are set, 1 means switch is in the up-position: -| Unit 1 | Unit 2 | Unit 3 | Unit 4 | Unit 5 | Unit 6 | Unit 7 | Unit 8 | Unit 9 | Unit 10 | +| Unit 1 | Unit 2 | Unit 3 | Unit 4 | Unit 5 | Unit 6 | Unit 7 | Unit 8 | Unit 9 | Unit 10 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | ### ESP01/ESP8266 + #### Pre-requisites + To upload the sketch to the ESP you need to install a few things to your arduino IDE. -- Install the ESP8266 board to your Arduino IDE. You can follow [this tutorial](https://randomnerdtutorials.com/how-to-install-esp8266-board-arduino-ide/) -- Install the arduino ESP8266 littleFS plugin to use the file system of the ESP, you can follow [this tutorial](https://randomnerdtutorials.com/install-esp8266-nodemcu-littlefs-arduino/) + +- Install the ESP8266 board to your Arduino IDE. You can follow [this tutorial](https://randomnerdtutorials.com/how-to-install-esp8266-board-arduino-ide/) +- Install the arduino ESP8266 littleFS plugin to use the file system of the ESP, you can follow [this tutorial](https://randomnerdtutorials.com/install-esp8266-nodemcu-littlefs-arduino/) - Install the following libraries via Library Manager: - - [ArduinoJSON](https://github.com/bblanchon/ArduinoJson) - Version: 7.0.3 + - [ArduinoJSON](https://github.com/bblanchon/ArduinoJson) - Version: 7.0.4 - [ESPAsyncWebSrv](https://github.com/dvarrel/ESPAsyncWebSrv) - Version: 1.2.7 - Dependencies which should be installed automatically: - [ESPAsyncTCP](https://github.com/dvarrel/ESPAsyncTCP) @@ -95,13 +112,14 @@ To upload the sketch to the ESP you need to install a few things to your arduino - [LinkedList](https://github.com/ivanseidel/LinkedList) - Version: 1.3.3 - [WiFiManager](https://github.com/tzapu/WiFiManager) - Version: 2.0.17 -To upload sketches to the ESP8266 you can either use an [Arduino Uno](https://create.arduino.cc/projecthub/pratikdesai/how-to-program-esp8266-esp-01-module-with-arduino-uno-598166) or you can buy a dedicated programmer. It is highly recommend getting a programmer as it makes uploading programs onto the ESP8266 much faster. +To upload sketches to the ESP8266 you can either use an [Arduino Uno](https://create.arduino.cc/projecthub/pratikdesai/how-to-program-esp8266-esp-01-module-with-arduino-uno-598166) or you can buy a dedicated programmer. It is highly recommend getting a programmer as it makes uploading programs onto the ESP8266 much faster. -> Note: Be wary of ESP8266 programmers that are available which allow USB connection to your PC which may not have programming abilities. Typically extra switches are available so that the ESP8266 can be put in programming mode, although you can modify the programmer through a simple solder job to allow it to enter programming mode. Examples can be found in the customer reviews of [Amazon](https://www.amazon.co.uk/gp/product/B078J7LDLY/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1). +> Note: Be wary of ESP8266 programmers that are available which allow USB connection to your PC which may not have programming abilities. Typically extra switches are available so that the ESP8266 can be put in programming mode, although you can modify the programmer through a simple solder job to allow it to enter programming mode. Examples can be found in the customer reviews of [Amazon](https://www.amazon.co.uk/gp/product/B078J7LDLY/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1). > Alternatively, you can get a dedicated programmer from Amazon such as [this one](https://www.amazon.co.uk/dp/B083QHJW21). This is also available on [AliExpress](https://www.aliexpress.com/item/1005001793822720.html?spm=a2g0o.detail.0.0.48622aefV0Zv89&mp=1) if you are willing to wait a while for it. #### Uploading the Static Assets via LittleFS + There are static files located [here](./ESPMaster/data/) in the `data` folder of ESPMaster which will need to be uploaded. These make up the website that will be accessible on your WiFi so you can update the Split-Flap display. Open the sketch `ESPMaster.ino` in the `ESPMaster` folder, change your board to "Generic ESP8266 Module", choose the correct COM-port and click: @@ -113,22 +131,25 @@ This uploads the website onto the ESP8266's file system. **NOTE:** No sketch has been uploaded yet! Only the static files. At the time of writing, this will also only work on an older version of Arduino IDE < version 2. The latest Arduino IDE broke support for Plugins such as the LittleFS plugin. #### Updating Settings of the Sketch -There are several options in the Sketch you can modify to customise or change the behaviour of the display. These are marked in the code as "Configurable". + +There are several options in the Sketch you can modify to customise or change the behaviour of the display. These are marked in the code as "Configurable". By default, the system will run in an "Access Point" mode where you will be able to connect to the display and put in WiFi credentials directly. This means if you WiFi changes, you don't have to re-upload a new sketch. Screenshot of the WiFi setup portal: ![Screenshot WiFi Portal](./Images/Access-Point-Screenshot.jpg) Alternatively, you can specify credentials directly. You can go ahead and change the credentials in these variables: + ```c++ const char* wifiDirectSsid = ""; const char* wifiDirectPassword = ""; ``` -You will also need to change the WiFi Mode in the code via changing this variable to "DIRECT": +You will also need to change the WiFi Mode in the code via changing this variable to `true`: + ```c++ -//Option to either direct connect to a WiFi Network or setup a AP to configure WiFi. Options: AP or DIRECT -#define WIFI_SETUP_MODE DIRECT +//Option to either direct connect to a WiFi Network or setup a AP to configure WiFi. Default: false (puts device in AP mode) +#define WIFI_USE_DIRECT false ``` You will also want to change the `timezoneString` to your time zone. You can find the TZ database names here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones @@ -136,6 +157,7 @@ You will also want to change the `timezoneString` to your time zone. You can fin You can also modify the date and clock format easily by using this table: https://github.com/ropg/ezTime#datetime There are several helper `define` variables to help during debugging/running: + - **SERIAL_ENABLE** - Use this to enable Serial output lines for tracking executing code - **OTA_ENABLE** @@ -144,12 +166,38 @@ There are several helper `define` variables to help during debugging/running: - **UNIT_CALLS_DISABLE** - Use this to disable the communication with the Arduino Nano Units. This will mean you can check code over function for the ESP module. +#### Experiments + +In the main Sketch under "Configurable Defines", an "EXPERIMENTAL" section has been included. This section has been created for features that are things that can be changed and trialled however aren't going to be necessary to be changed for general use. + +##### Static IP Address + +A feature request of being able to set a Static IP Address was created by [beroliv](https://github.com/beroliv) (thank you for the suggestion). This was to get around issues whereby in some routers, there was issues in being able to do this. + +Code has been added to be able to set a Static IP Address on device. To do this: + +1. Set the `WIFI_STATIC_IP` variable to `true` (defaulted to `false`) +2. Update the following settings as necessary for your needs: + + ```c++ + IPAddress wifiDeviceStaticIp(192, 168, 1, 100); + + IPAddress wifiRouterGateway(192, 168, 1, 1); + IPAddress wifiSubnet(255, 255, 0, 0); + + IPAddress wifiPrimaryDns(8, 8, 8, 8); + ``` + +**Suggestion:** Set your device up with a Static IP via your router if possible and to avoid conflicts on your network, however feel free to run this code if you are not able to. Testing this functionality showed it does work in both AP/Direct WiFi modes. + #### Sketch Upload + So far we've only uploaded static files to the ESP8266. You now need to `Upload` the sketch to the ESP8266. Click on Upload and the ESP8266 will be upadted with the sketch and you are done. Stick the ESP8266 onto the first unit's PCB and navigate to the IP-address the ESP8266 is getting assigned from your router. ### Common Problems + - If the ESP is not talking to the units correctly, check the `UNITSAMOUNT` in the `ESPMaster.ino`. The amount of units connected has to match. -- Ensure you upload the sketch and the LittleFS sketch upload to the ESP8266. -- When the system is powered, your Hall Sensor should only light up when a magnet is nearby. +- Ensure you upload the sketch and the LittleFS sketch upload to the ESP8266. +- When the system is powered, your Hall Sensor should only light up when a magnet is nearby. - Ensure you are running an older version of Arduino IDE to be able to upload static files to the device. You will need a version prior to version 2.x. -- User [@beroliv](https://github.com/beroliv) has reported having issues with WiFi connections. One solution they have proposed is soldering a wire to the antenna to be able to extend its range by creating an antenna. Here is the [link](https://www.stall.biz/project/verbesserte-wlan-konnektivitaet-mit-externen-antennen-fuer-wiffi-weatherman-und-andere-module-mit-esp8266/) (in German but Google Translate does a good job for other languages) they provided to detail the solution. Please take care when carrying out this solution. Thank you for the information [@beroliv](https://github.com/beroliv)! \ No newline at end of file +- User [@beroliv](https://github.com/beroliv) has reported having issues with WiFi connections. One solution they have proposed is soldering a wire to the antenna to be able to extend its range by creating an antenna. Here is the [link](https://www.stall.biz/project/verbesserte-wlan-konnektivitaet-mit-externen-antennen-fuer-wiffi-weatherman-und-andere-module-mit-esp8266/) (in German but Google Translate does a good job for other languages) they provided to detail the solution. Please take care when carrying out this solution. Thank you for the information [@beroliv](https://github.com/beroliv)!