Added basic WebSocket Functionality
This commit is contained in:
Vendored
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"port": "",
|
||||
"configuration": "",
|
||||
"output": "build",
|
||||
"board": "",
|
||||
"programmer": "",
|
||||
"useProgrammer": false,
|
||||
"configurationRequired": false,
|
||||
"monitorPortSettings": {
|
||||
"port": "",
|
||||
"baudRate": 115200,
|
||||
"lineEnding": "\r\n",
|
||||
"dataBits": 8,
|
||||
"parity": "none",
|
||||
"stopBits": "one"
|
||||
}
|
||||
}
|
||||
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"C:/Users/Admin/Documents/Arduino/libraries/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE"
|
||||
],
|
||||
"compilerPath": null,
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++14",
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"C_Cpp.default.compilerPath": "",
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*KC868-A6 DS1307 CODE*/
|
||||
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.isrunning()) {
|
||||
Serial.println("RTC is NOT running, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(" (");
|
||||
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
|
||||
Serial.print(") ");
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" since midnight 1/1/1970 = ");
|
||||
Serial.print(now.unixtime());
|
||||
Serial.print("s = ");
|
||||
Serial.print(now.unixtime() / 86400L);
|
||||
Serial.println("d");
|
||||
|
||||
// calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
|
||||
DateTime future (now + TimeSpan(7,12,30,6));
|
||||
|
||||
Serial.print(" now + 7d + 12h + 30m + 6s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
#include "PCF8574.h"
|
||||
|
||||
// Set i2c address
|
||||
PCF8574 pcf8574(0x22,4,15);
|
||||
unsigned long timeElapsed;
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
pcf8574.pinMode(P0, INPUT);
|
||||
pcf8574.pinMode(P1, INPUT);
|
||||
pcf8574.pinMode(P2, INPUT);
|
||||
pcf8574.pinMode(P3, INPUT);
|
||||
pcf8574.pinMode(P4, INPUT);
|
||||
pcf8574.pinMode(P5, INPUT);
|
||||
pcf8574.pinMode(P6, INPUT);
|
||||
pcf8574.pinMode(P7, INPUT);
|
||||
|
||||
Serial.print("Init pcf8574...");
|
||||
if (pcf8574.begin()){
|
||||
Serial.println("OK");
|
||||
}else{
|
||||
Serial.println("KO");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t val1 = pcf8574.digitalRead(P0);
|
||||
uint8_t val2 = pcf8574.digitalRead(P1);
|
||||
uint8_t val3 = pcf8574.digitalRead(P2);
|
||||
uint8_t val4 = pcf8574.digitalRead(P3);
|
||||
uint8_t val5 = pcf8574.digitalRead(P4);
|
||||
uint8_t val6 = pcf8574.digitalRead(P5);
|
||||
uint8_t val7 = pcf8574.digitalRead(P6);
|
||||
uint8_t val8 = pcf8574.digitalRead(P7);
|
||||
if (val1==LOW) Serial.println("KEY1 PRESSED");
|
||||
if (val2==LOW) Serial.println("KEY2 PRESSED");
|
||||
if (val3==LOW) Serial.println("KEY3 PRESSED");
|
||||
if (val4==LOW) Serial.println("KEY4 PRESSED");
|
||||
if (val5==LOW) Serial.println("KEY5 PRESSED");
|
||||
if (val6==LOW) Serial.println("KEY6 PRESSED");
|
||||
if (val7==LOW) Serial.println("KEY7 PRESSED");
|
||||
if (val8==LOW) Serial.println("KEY8 PRESSED");
|
||||
delay(300);
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
Blink led on PIN0
|
||||
by Mischianti Renzo <http://www.mischianti.org>
|
||||
|
||||
https://www.mischianti.org/2019/01/02/pcf8574-i2c-digital-i-o-expander-fast-easy-usage/
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "PCF8574.h"
|
||||
|
||||
// Set i2c address
|
||||
PCF8574 pcf8574(0x24,4,15);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
// delay(1000);
|
||||
|
||||
// Set pinMode to OUTPUT
|
||||
pcf8574.pinMode(P0, OUTPUT);
|
||||
pcf8574.pinMode(P1, OUTPUT);
|
||||
pcf8574.pinMode(P2, OUTPUT);
|
||||
pcf8574.pinMode(P3, OUTPUT);
|
||||
pcf8574.pinMode(P4, OUTPUT);
|
||||
pcf8574.pinMode(P5, OUTPUT);
|
||||
|
||||
|
||||
pcf8574.digitalWrite(P0, HIGH);
|
||||
pcf8574.digitalWrite(P1, HIGH);
|
||||
pcf8574.digitalWrite(P2, HIGH);
|
||||
pcf8574.digitalWrite(P3, HIGH);
|
||||
pcf8574.digitalWrite(P4, HIGH);
|
||||
pcf8574.digitalWrite(P5, HIGH);
|
||||
|
||||
Serial.print("Init pcf8574...");
|
||||
if (pcf8574.begin()){
|
||||
Serial.println("OK");
|
||||
}else{
|
||||
Serial.println("KO");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(300);
|
||||
pcf8574.digitalWrite(P0, LOW);
|
||||
delay(300);
|
||||
pcf8574.digitalWrite(P1, LOW);
|
||||
delay(300);
|
||||
pcf8574.digitalWrite(P2, LOW);
|
||||
delay(300);
|
||||
pcf8574.digitalWrite(P3, LOW);
|
||||
delay(300);
|
||||
pcf8574.digitalWrite(P4, LOW);
|
||||
delay(300);
|
||||
pcf8574.digitalWrite(P5, LOW);
|
||||
delay(300);
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*KC868-A6 DS1307 CODE*/
|
||||
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
|
||||
#include "RTClib.h"
|
||||
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
|
||||
void setup () {
|
||||
Serial.begin(57600);
|
||||
|
||||
#ifndef ESP8266
|
||||
while (!Serial); // wait for serial port to connect. Needed for native USB
|
||||
#endif
|
||||
|
||||
if (! rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
Serial.flush();
|
||||
while (1) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.isrunning()) {
|
||||
Serial.println("RTC is NOT running, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
// When time needs to be re-set on a previously configured device, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
}
|
||||
|
||||
void loop () {
|
||||
DateTime now = rtc.now();
|
||||
|
||||
Serial.print(now.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(now.day(), DEC);
|
||||
Serial.print(" (");
|
||||
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
|
||||
Serial.print(") ");
|
||||
Serial.print(now.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(now.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.print(" since midnight 1/1/1970 = ");
|
||||
Serial.print(now.unixtime());
|
||||
Serial.print("s = ");
|
||||
Serial.print(now.unixtime() / 86400L);
|
||||
Serial.println("d");
|
||||
|
||||
// calculate a date which is 7 days, 12 hours, 30 minutes, and 6 seconds into the future
|
||||
DateTime future (now + TimeSpan(7,12,30,6));
|
||||
|
||||
Serial.print(" now + 7d + 12h + 30m + 6s: ");
|
||||
Serial.print(future.year(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.month(), DEC);
|
||||
Serial.print('/');
|
||||
Serial.print(future.day(), DEC);
|
||||
Serial.print(' ');
|
||||
Serial.print(future.hour(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.minute(), DEC);
|
||||
Serial.print(':');
|
||||
Serial.print(future.second(), DEC);
|
||||
Serial.println();
|
||||
|
||||
Serial.println();
|
||||
delay(3000);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
Vendored
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"port": "COM8",
|
||||
"configuration": "UploadSpeed=921600,CPUFreq=240,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=none,PSRAM=disabled,LoopCore=1,EventsCore=1,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default",
|
||||
"output": "build",
|
||||
"board": "esp32:esp32:esp32",
|
||||
"programmer": "",
|
||||
"useProgrammer": false,
|
||||
"configurationRequired": true,
|
||||
"monitorPortSettings": {
|
||||
"port": "COM8",
|
||||
"baudRate": 115200,
|
||||
"lineEnding": "\r\n",
|
||||
"dataBits": 8,
|
||||
"parity": "none",
|
||||
"stopBits": "one"
|
||||
}
|
||||
}
|
||||
Vendored
-101
@@ -1,101 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Arduino",
|
||||
"includePath": [
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\cores\\esp32/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\variants\\esp32/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\WiFi\\src/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\Network\\src/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\libraries\\AsyncMqttClient\\src/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\libraries\\Async_TCP\\src/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\libraries\\ArduinoJson\\src/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\FS\\src/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\SPIFFS\\src/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\Wire\\src/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\libraries\\Adafruit_PCF8574/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\libraries\\Adafruit_BusIO/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\SPI\\src/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\libraries/**",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\4. Bell Systems\\1. Main Projects\\Project - Vesper/**",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.3-cfea4f7c-v1\\esp32\\include/**"
|
||||
],
|
||||
"forcedInclude": [
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\cores\\esp32\\Arduino.h"
|
||||
],
|
||||
"compilerPath": "C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp-x32\\2405/bin/xtensa-esp32-elf-g++",
|
||||
"compilerArgs": [
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp-x32\\2405/bin/xtensa-esp32-elf-g++",
|
||||
"-MMD",
|
||||
"-c",
|
||||
"@C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.3-cfea4f7c-v1\\esp32/flags/cpp_flags",
|
||||
"-w",
|
||||
"-Os",
|
||||
"-Werror=return-type",
|
||||
"-DF_CPU=240000000L",
|
||||
"-DARDUINO=10607",
|
||||
"-DARDUINO_ESP32_DEV",
|
||||
"-DARDUINO_ARCH_ESP32",
|
||||
"-DARDUINO_BOARD=\"ESP32_DEV\"",
|
||||
"-DARDUINO_VARIANT=\"esp32\"",
|
||||
"-DARDUINO_PARTITION_default",
|
||||
"-DARDUINO_HOST_OS=\"windows\"",
|
||||
"-DARDUINO_FQBN=\"esp32:esp32:esp32:UploadSpeed=921600,CPUFreq=240,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=none,PSRAM=disabled,LoopCore=1,EventsCore=1,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default\"",
|
||||
"-DESP32=ESP32",
|
||||
"-DCORE_DEBUG_LEVEL=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=0",
|
||||
"@C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.3-cfea4f7c-v1\\esp32/flags/defines",
|
||||
"-IC:\\Users\\espi_\\Documents\\Arduino\\4. Bell Systems\\1. Main Projects\\Project - Vesper",
|
||||
"-iprefix",
|
||||
"C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.3-cfea4f7c-v1\\esp32/include/",
|
||||
"@C:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.3-cfea4f7c-v1\\esp32/flags/includes",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp32-arduino-libs\\idf-release_v5.3-cfea4f7c-v1\\esp32/qio_qspi/include",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\cores\\esp32",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\variants\\esp32",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\WiFi\\src",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\Network\\src",
|
||||
"-IC:\\Users\\espi_\\Documents\\Arduino\\libraries\\AsyncMqttClient\\src",
|
||||
"-IC:\\Users\\espi_\\Documents\\Arduino\\libraries\\Async_TCP\\src",
|
||||
"-IC:\\Users\\espi_\\Documents\\Arduino\\libraries\\ArduinoJson\\src",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\FS\\src",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\SPIFFS\\src",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\Wire\\src",
|
||||
"-IC:\\Users\\espi_\\Documents\\Arduino\\libraries\\Adafruit_PCF8574",
|
||||
"-IC:\\Users\\espi_\\Documents\\Arduino\\libraries\\Adafruit_BusIO",
|
||||
"-IC:\\Users\\espi_\\AppData\\Local\\Arduino15\\packages\\esp32\\hardware\\esp32\\3.1.1\\libraries\\SPI\\src",
|
||||
"@C:\\Users\\espi_\\Documents\\Arduino\\4. Bell Systems\\1. Main Projects\\Project - Vesper\\build/build_opt.h",
|
||||
"@C:\\Users\\espi_\\Documents\\Arduino\\4. Bell Systems\\1. Main Projects\\Project - Vesper\\build/file_opts",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\4. Bell Systems\\1. Main Projects\\Project - Vesper\\build\\sketch\\Project - Vesper.ino.cpp",
|
||||
"-o",
|
||||
"C:\\Users\\espi_\\Documents\\Arduino\\4. Bell Systems\\1. Main Projects\\Project - Vesper\\build\\sketch\\Project - Vesper.ino.cpp.o"
|
||||
],
|
||||
"defines": [
|
||||
"F_CPU=240000000L",
|
||||
"ARDUINO=10607",
|
||||
"ARDUINO_ESP32_DEV",
|
||||
"ARDUINO_ARCH_ESP32",
|
||||
"ARDUINO_BOARD=\"ESP32_DEV\"",
|
||||
"ARDUINO_VARIANT=\"esp32\"",
|
||||
"ARDUINO_PARTITION_default",
|
||||
"ARDUINO_HOST_OS=\"windows\"",
|
||||
"ARDUINO_FQBN=\"esp32:esp32:esp32:UploadSpeed=921600,CPUFreq=240,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=none,PSRAM=disabled,LoopCore=1,EventsCore=1,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default\"",
|
||||
"ESP32=ESP32",
|
||||
"CORE_DEBUG_LEVEL=0",
|
||||
"ARDUINO_RUNNING_CORE=1",
|
||||
"ARDUINO_EVENT_RUNNING_CORE=1",
|
||||
"ARDUINO_USB_CDC_ON_BOOT=0",
|
||||
"ARDUINO_BOARD=\\\"ESP32_DEV\\\"\"",
|
||||
"ARDUINO_VARIANT=\\\"esp32\\\"\"",
|
||||
"ARDUINO_HOST_OS=\\\"windows\\\"\"",
|
||||
"ARDUINO_FQBN=\\\"esp32:esp32:esp32:UploadSpeed=921600,CPUFreq=240,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=none,PSRAM=disabled,LoopCore=1,EventsCore=1,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default\\\"\"",
|
||||
"ARDUINO_CORE_BUILD",
|
||||
"USBCON"
|
||||
],
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
@@ -16,30 +16,45 @@ JsonDocument handleJSON(char * payload) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
void replyOnWebSocket(AsyncWebSocketClient *client, String list) {
|
||||
client->text(list);
|
||||
}
|
||||
|
||||
// Handles the JSON Commands
|
||||
void handleCommand(JsonDocument json, AsyncWebSocketClient *client = nullptr){
|
||||
|
||||
String cmd = json["cmd"];
|
||||
JsonVariant contents = json["contents"];
|
||||
|
||||
if (cmd == "playback") {
|
||||
player.command(contents);
|
||||
} else if (cmd == "set_melody") {
|
||||
player.setMelodyAttributes(contents);
|
||||
player.loadMelodyInRAM(melody_steps);
|
||||
} else if (cmd == "list_melodies") {
|
||||
String list = listFilesAsJson("/melodies");
|
||||
PublishMqtt(list.c_str());
|
||||
if (client) {
|
||||
replyOnWebSocket(client, list); // Only reply via WS if client exists
|
||||
}
|
||||
} else if (cmd == "set_relay_timers") {
|
||||
updateRelayTimings(contents);
|
||||
} else if (cmd == "add_melody"){
|
||||
addMelody(contents);
|
||||
} else {
|
||||
LOG_WARNING("Unknown Command Received");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Subscribes to certain topics on the MQTT Server.
|
||||
void SuscribeMqtt() {
|
||||
|
||||
String topicPlayback = String("vesper/") + DEV_ID + "/control/playback";
|
||||
String topicSetMelody = String("vesper/") + DEV_ID + "/control/setMelody";
|
||||
String topicAddMelody = String("vesper/") + DEV_ID + "/control/addMelody";
|
||||
String topicAddSchedule = String("vesper/") + DEV_ID + "/control/addSchedule";
|
||||
String topicRelayTimers = String("vesper/") + DEV_ID + "/control/settings/relayTimers";
|
||||
|
||||
uint16_t control_id = mqttClient.subscribe(topicPlayback.c_str(), 2);
|
||||
LOG_INFO("Subscribing to Playback Control topic, QoS 2, packetId: %d", control_id);
|
||||
|
||||
uint16_t set_melody_id = mqttClient.subscribe(topicSetMelody.c_str(), 2);
|
||||
LOG_INFO("Subscribing to Set-Melody topic, QoS 2, packetId: %d", set_melody_id);
|
||||
|
||||
// doesn't work yet:
|
||||
uint16_t add_melody_id = mqttClient.subscribe(topicAddMelody.c_str(), 2);
|
||||
LOG_INFO("Subscribing to Add-Melody topic, QoS 2, packetId: %d", add_melody_id);
|
||||
|
||||
uint16_t add_schedule_id = mqttClient.subscribe(topicAddSchedule.c_str(), 2);
|
||||
LOG_INFO("Subscribing to Add-Schedule topic, QoS 2, packetId: %d", add_schedule_id);
|
||||
|
||||
uint16_t relay_timers_id = mqttClient.subscribe(topicRelayTimers.c_str(), 2);
|
||||
LOG_INFO("Subscribing to Relay-Timers topic, QoS 2, packetId: %d", relay_timers_id);
|
||||
String command = String("vesper/") + DEV_ID + "/control";
|
||||
uint16_t command_id = mqttClient.subscribe(command.c_str(), 2);
|
||||
LOG_INFO("Subscribing to Command topic, QoS 2, packetId: %d", command_id);
|
||||
|
||||
}
|
||||
|
||||
@@ -47,41 +62,36 @@ void SuscribeMqtt() {
|
||||
// Could move logic out of this into a dedicated function.
|
||||
void OnMqttReceived(char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
|
||||
String topicPlayback = String("vesper/") + DEV_ID + "/control/playback";
|
||||
String topicSetMelody = String("vesper/") + DEV_ID + "/control/setMelody";
|
||||
String topicAddMelody = String("vesper/") + DEV_ID + "/control/addMelody";
|
||||
String topicAddSchedule = String("vesper/") + DEV_ID + "/control/addSchedule";
|
||||
String topicRelayTimers = String("vesper/") + DEV_ID + "/control/settings/relayTimers";
|
||||
String command = String("vesper/") + DEV_ID + "/control";
|
||||
|
||||
// Don't know what this is. Check it out later.
|
||||
//String payloadContent = String(payload).substring(0, len);
|
||||
|
||||
if (String(topic) == topicPlayback){
|
||||
player.command(payload);
|
||||
if (String(topic) == command){
|
||||
JsonDocument json = handleJSON(payload);
|
||||
handleCommand(json);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handles incoming WebSocket messages on subscribed topics.
|
||||
// Could move logic out of this into a dedicated function.
|
||||
void onWebSocketReceived(AsyncWebSocketClient *client, void *arg, uint8_t *data, size_t len) {
|
||||
AwsFrameInfo *info = (AwsFrameInfo*)arg;
|
||||
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
|
||||
data[len] = '\0'; // Null-terminate the received data
|
||||
Serial.printf("Received message: %s\n", (char*)data);
|
||||
|
||||
JsonDocument json = handleJSON((char*)data);
|
||||
handleCommand(json, client);
|
||||
|
||||
else if (String(topic) == topicSetMelody) {
|
||||
player.setMelodyAttributes(handleJSON(payload));
|
||||
player.loadMelodyInRAM(melody_steps);
|
||||
}
|
||||
}
|
||||
|
||||
else if (String(topic) == topicAddMelody) {
|
||||
// Handle adding melody
|
||||
LOG_INFO("Adding melody...");
|
||||
// You can call a function here to handle adding the melody
|
||||
}
|
||||
|
||||
else if (String(topic) == topicAddSchedule) {
|
||||
updateSchedule(handleJSON(payload));
|
||||
}
|
||||
|
||||
else if (String(topic) == topicRelayTimers) {
|
||||
updateRelayTimings(handleJSON(payload));
|
||||
}
|
||||
|
||||
else {
|
||||
// Handle unknown topics
|
||||
LOG_WARNING("Unknown topic received.");
|
||||
void onWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
|
||||
if (type == WS_EVT_DATA) {
|
||||
onWebSocketReceived(client, arg, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,21 +12,17 @@ String GetPayloadContent(char * data, size_t len) {
|
||||
return content;
|
||||
}
|
||||
|
||||
void ConnectToMqtt()
|
||||
{
|
||||
void ConnectToMqtt() {
|
||||
LOG_INFO("Connecting to MQTT...");
|
||||
mqttClient.connect();
|
||||
}
|
||||
|
||||
void OnMqttConnect(bool sessionPresent)
|
||||
{
|
||||
void OnMqttConnect(bool sessionPresent) {
|
||||
LOG_INFO("Connected to MQTT.");
|
||||
//LOG_INFO("Session present: %s", sessionPresent ? "Yes":"No");
|
||||
SuscribeMqtt();
|
||||
}
|
||||
|
||||
void OnMqttDisconnect(AsyncMqttClientDisconnectReason reason)
|
||||
{
|
||||
void OnMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||
LOG_WARNING("Disconnected from MQTT.");
|
||||
|
||||
if(WiFi.isConnected())
|
||||
@@ -35,51 +31,44 @@ void OnMqttDisconnect(AsyncMqttClientDisconnectReason reason)
|
||||
}
|
||||
}
|
||||
|
||||
void OnMqttSubscribe(uint16_t packetId, uint8_t qos)
|
||||
{
|
||||
void OnMqttSubscribe(uint16_t packetId, uint8_t qos) {
|
||||
LOG_INFO("Subscribe acknowledged. PacketID: %d / QoS: %d", packetId, qos);
|
||||
}
|
||||
|
||||
void OnMqttUnsubscribe(uint16_t packetId)
|
||||
{
|
||||
void OnMqttUnsubscribe(uint16_t packetId) {
|
||||
LOG_INFO("Unsubscribe Acknowledged. PacketID: %d",packetId);
|
||||
}
|
||||
|
||||
void OnMqttPublish(uint16_t packetId)
|
||||
{
|
||||
void OnMqttPublish(uint16_t packetId) {
|
||||
LOG_INFO("Publish Acknowledged. PacketID: %d", packetId);
|
||||
}
|
||||
|
||||
void ConnectWiFi_STA(bool useStaticIP = false)
|
||||
{
|
||||
Serial.println("");
|
||||
void ConnectWiFi_STA(bool useStaticIP = true) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
if(useStaticIP) {
|
||||
WiFi.config(ip, gateway, subnet);
|
||||
WiFi.setHostname(hostname);
|
||||
}
|
||||
WiFi.begin(ssid, password);
|
||||
//WiFi.begin(ssid, password);
|
||||
WiFi.begin();
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
Serial.print('.');
|
||||
delay(10);
|
||||
}
|
||||
|
||||
if (LOG_LEVEL_ENABLED(LOG_LEVEL_INFO)){
|
||||
Serial.println("");
|
||||
Serial.print("Initiating STA:\t");
|
||||
Serial.print("NIGGA - Initiating STA:\t");
|
||||
Serial.println(ssid);
|
||||
Serial.print("IP address:\t");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectWiFi_AP(bool useStaticIP = false)
|
||||
{
|
||||
void ConnectWiFi_AP(bool useStaticIP = false) {
|
||||
Serial.println("");
|
||||
WiFi.mode(WIFI_AP);
|
||||
while(!WiFi.softAP(ssid, password))
|
||||
{
|
||||
while(!WiFi.softAP(ssid, password)) {
|
||||
Serial.println(".");
|
||||
delay(100);
|
||||
}
|
||||
@@ -95,26 +84,53 @@ void ConnectWiFi_AP(bool useStaticIP = false)
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
LOG_INFO("[WiFi-event] event: %d\n", event);
|
||||
void NetworkEvent(arduino_event_id_t event, arduino_event_info_t info) {
|
||||
LOG_INFO("(NET) event: %d\n", event);
|
||||
IPAddress ip = WiFi.localIP();
|
||||
switch(event)
|
||||
{
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
Serial.print("[INFO] - WiFi connected. IP Address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
LOG_DEBUG("WiFi connected. IP Address: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
||||
//xTimerStop(wifiReconnectTimer, 0);
|
||||
ConnectToMqtt();
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
LOG_WARNING("WiFi Lost Connection! :()");
|
||||
xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
|
||||
LOG_WARNING("WiFi Lost Connection! :(");
|
||||
xTimerStop(mqttReconnectTimer, 0);
|
||||
xTimerStart(wifiReconnectTimer, 0);
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
LOG_DEBUG("ETH Started");
|
||||
ETH.setHostname(hostname);
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
LOG_DEBUG("ETH Connected !");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
LOG_INFO("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif));
|
||||
WiFi.disconnect(true);
|
||||
ConnectToMqtt();
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_LOST_IP:
|
||||
LOG_WARNING("ETH Lost IP");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
LOG_WARNING("ETH Disconnected");
|
||||
xTimerStop(mqttReconnectTimer, 0);
|
||||
xTimerStart(wifiReconnectTimer, 0);
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_STOP:
|
||||
LOG_INFO("ETH Stopped");
|
||||
xTimerStop(mqttReconnectTimer, 0);
|
||||
xTimerStart(wifiReconnectTimer, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InitMqtt()
|
||||
{
|
||||
void InitMqtt() {
|
||||
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(ConnectToMqtt));
|
||||
wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(5000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(ConnectWiFi_STA));
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// Timed Function. Will Run ONCE per 10 sec
|
||||
void schedule_timer() {
|
||||
|
||||
// Tick the calendar to perform internal functions.
|
||||
// (Updates current time. Updates Daily Schedule if its Midnight)
|
||||
timekeeper.tick();
|
||||
timekeeper.checkAndRunSchedule(player);
|
||||
// This is here for debugging purposes only.
|
||||
timekeeper.printTimeNow();
|
||||
|
||||
}
|
||||
|
||||
// void dailyScheduleCheck(std::vector<ScheduleEntry>){
|
||||
|
||||
// }
|
||||
@@ -54,7 +54,6 @@ void relayControlTask(void *param) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop_playback(std::vector<uint16_t> &melody_steps) {
|
||||
|
||||
while(player.isPlaying && !player.isPaused){
|
||||
@@ -72,7 +71,6 @@ void loop_playback(std::vector<uint16_t> &melody_steps) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Function to activate relays for a specific note
|
||||
void itsHammerTime(uint16_t note) {
|
||||
uint64_t now = millis();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+21
-214
@@ -13,7 +13,7 @@ public:
|
||||
uint32_t loop_duration = 0; // Duration of the playback per segment
|
||||
uint32_t interval = 0; // Indicates the Duration of the Interval between finished segments, IF "inf" is true
|
||||
bool infinite_play = false; // Infinite Loop Indicator (If True the melody will loop forever or until stoped, with pauses of "interval" in between loops)
|
||||
bool isPlaying = false;; // Indicates if the Melody is actually Playing right now.
|
||||
bool isPlaying = false; // Indicates if the Melody is actually Playing right now.
|
||||
bool isPaused = false; // If playing, indicates if the Melody is Paused
|
||||
uint64_t startTime = 0; // The time-point the Melody started Playing
|
||||
uint64_t loopStartTime = 0; // The time-point the current segment started Playing
|
||||
@@ -51,19 +51,20 @@ public:
|
||||
}
|
||||
|
||||
// Handles Incoming Commands to PLAY or STOP
|
||||
void command(char * command){
|
||||
LOG_DEBUG("Incoming Command: %s",command);
|
||||
if (command[0] == '1') {
|
||||
void command(JsonVariant content){
|
||||
String action = content["action"];
|
||||
LOG_DEBUG("Incoming Command: %s", action);
|
||||
if (action == "play") {
|
||||
play();
|
||||
PublishMqtt("OK - PLAY");
|
||||
} else if (command[0] == '0') {
|
||||
} else if (action == "stop") {
|
||||
forceStop();
|
||||
PublishMqtt("OK - STOP");
|
||||
}
|
||||
}
|
||||
|
||||
// Sets incoming Attributes for the Melody, into the class' variables.
|
||||
void setMelodyAttributes(JsonDocument doc){
|
||||
void setMelodyAttributes(JsonVariant doc){
|
||||
|
||||
if (doc.containsKey("name")) {
|
||||
name = doc["name"].as<const char*>();
|
||||
@@ -98,229 +99,35 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
// Loads the Selected melody from a .bin file, into RAM
|
||||
|
||||
// Loads the Selected melody from a .bin file on SD into RAM
|
||||
void loadMelodyInRAM(std::vector<uint16_t> &melody_steps) {
|
||||
String filePath = "/melodies/" + String(name.c_str()) + ".bin";
|
||||
|
||||
LOG_INFO("Loading Melody.");
|
||||
std::string filePath = "/" + name + ".bin";
|
||||
|
||||
File bin_file = SPIFFS.open(filePath.c_str(), "r");
|
||||
File bin_file = SD.open(filePath.c_str(), FILE_READ);
|
||||
if (!bin_file) {
|
||||
LOG_ERROR("Failed to Open File");
|
||||
LOG_ERROR("Failed to open file: %s", filePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t fileSize = bin_file.size();
|
||||
size_t steps = fileSize / 2;
|
||||
melody_steps.resize(steps);
|
||||
|
||||
LOG_DEBUG("Opened File, size: %zu - Steps: %zu",fileSize,steps)
|
||||
|
||||
for (size_t i=0; i<steps; i++){
|
||||
melody_steps[i] = bin_file.read() << 8 | bin_file.read();
|
||||
LOG_DEBUG("Current Step: %03d // HEX Value: 0x%04X", i, melody_steps[i]);
|
||||
}
|
||||
|
||||
LOG_DEBUG("Closing File");
|
||||
if (fileSize % 2 != 0) {
|
||||
LOG_ERROR("Invalid file size: %u (not a multiple of 2)", fileSize);
|
||||
bin_file.close();
|
||||
|
||||
// closing the file
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class TimeKeeper {
|
||||
private:
|
||||
|
||||
// holds the daily scheduled melodies
|
||||
struct ScheduleEntry {
|
||||
std::string mel;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint16_t speed;
|
||||
uint16_t duration;
|
||||
};
|
||||
|
||||
struct TimeNow {
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
};
|
||||
|
||||
std::vector<ScheduleEntry> dailySchedule;
|
||||
TimeNow now;
|
||||
|
||||
// update to current time
|
||||
void updateTime(){
|
||||
now.hour = getHour();
|
||||
now.minute = getMinute();
|
||||
now.second = getSecond();
|
||||
}
|
||||
|
||||
// Read the current Month's JSON file and add the daily entries to the dailySchedule
|
||||
void loadDailySchedule() {
|
||||
std::string filePath = "/" + getMonth() + ".json";
|
||||
File file = SPIFFS.open(filePath.c_str(), "r");
|
||||
if (!file) {
|
||||
LOG_ERROR("Failed to open file: %s\n", filePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Opened daily schedule file");
|
||||
StaticJsonDocument<8192> doc; // Adjust size based on expected JSON complexity
|
||||
DeserializationError error = deserializeJson(doc, file);
|
||||
file.close();
|
||||
melody_steps.resize(fileSize / 2);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse JSON: %s\n", error.c_str());
|
||||
return;
|
||||
for (size_t i = 0; i < melody_steps.size(); i++) {
|
||||
uint8_t high = bin_file.read();
|
||||
uint8_t low = bin_file.read();
|
||||
melody_steps[i] = (high << 8) | low;
|
||||
}
|
||||
|
||||
if (LOG_LEVEL_ENABLED(LOG_LEVEL_DEBUG)){
|
||||
String jsonString;
|
||||
serializeJsonPretty(doc, jsonString);
|
||||
LOG_DEBUG("Serialized JSON: /n%s",jsonString.c_str());
|
||||
}
|
||||
LOG_INFO("Melody Load Successful");
|
||||
|
||||
// Extract entries for the current day
|
||||
std::string currentDay = getDay();
|
||||
dailySchedule.clear(); // Clear previous day's schedule
|
||||
|
||||
LOG_DEBUG("Current Day: %s\n", currentDay.c_str());
|
||||
|
||||
if (doc.containsKey(currentDay.c_str())) {
|
||||
LOG_DEBUG("Doc contains key!");
|
||||
|
||||
// Check if the current day contains a single object or an array
|
||||
JsonVariant dayVariant = doc[currentDay.c_str()];
|
||||
|
||||
if (dayVariant.is<JsonArray>()) {
|
||||
// Handle case where the day contains an array of entries
|
||||
JsonArray dayEntries = dayVariant.as<JsonArray>();
|
||||
for (JsonObject entry : dayEntries) {
|
||||
ScheduleEntry schedule;
|
||||
schedule.mel = entry["name"].as<std::string>();
|
||||
schedule.hour = entry["hour"];
|
||||
schedule.minute = entry["minute"];
|
||||
schedule.speed = entry["speed"];
|
||||
schedule.duration = entry["duration"];
|
||||
dailySchedule.push_back(schedule);
|
||||
|
||||
LOG_INFO("Added Entry - Melody: %s, Hour: %d, Minute: %d, Speed: %d, Duration: %d\n",
|
||||
schedule.mel.c_str(), schedule.hour, schedule.minute, schedule.speed, schedule.duration);
|
||||
}
|
||||
} else if (dayVariant.is<JsonObject>()) {
|
||||
// Handle case where the day contains a single object
|
||||
JsonObject entry = dayVariant.as<JsonObject>();
|
||||
ScheduleEntry schedule;
|
||||
schedule.mel = entry["name"].as<std::string>();
|
||||
schedule.hour = entry["hour"];
|
||||
schedule.minute = entry["minute"];
|
||||
schedule.speed = entry["speed"];
|
||||
schedule.duration = entry["duration"];
|
||||
dailySchedule.push_back(schedule);
|
||||
|
||||
LOG_INFO("Added Single Entry - Melody: %s, Hour: %d, Minute: %d, Speed: %d, Duration: %d\n",
|
||||
schedule.mel.c_str(), schedule.hour, schedule.minute, schedule.speed, schedule.duration);
|
||||
} else {
|
||||
LOG_WARNING("Invalid data format for the current day.");
|
||||
}
|
||||
} else {
|
||||
LOG_INFO("No schedule found for today.");
|
||||
}
|
||||
}
|
||||
|
||||
// Calls "loadDailySchedule" and returns true ONCE per new day (00:00)
|
||||
bool newDayCheck() {
|
||||
|
||||
// Static variable to store whether we've already detected the new day
|
||||
static bool alreadyTriggered = false;
|
||||
// Check if it's midnight
|
||||
if (now.hour == 0 && now.minute == 0) {
|
||||
if (!alreadyTriggered) {
|
||||
// First time at midnight, trigger the event
|
||||
alreadyTriggered = true;
|
||||
LOG_DEBUG("New day detected, returning true.");
|
||||
loadDailySchedule();
|
||||
return true;
|
||||
} else {
|
||||
// It's still midnight, but we've already triggered
|
||||
LOG_DEBUG("Already triggered for today, returning false.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Reset the trigger after midnight has passed
|
||||
alreadyTriggered = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// get date and time data from the RTC module
|
||||
uint16_t getYear() { return rtc.now().year(); }
|
||||
std::string getMonth() { return monthName(rtc.now().month()); }
|
||||
std::string getDay() { return std::to_string(rtc.now().day()); }
|
||||
uint8_t getHour() { return rtc.now().hour(); }
|
||||
uint8_t getMinute() { return rtc.now().minute(); }
|
||||
uint8_t getSecond() { return rtc.now().second(); }
|
||||
|
||||
// turn months from decimal to char*
|
||||
std::string monthName(uint8_t monthNumber) {
|
||||
const char* monthNames[] = {
|
||||
"jan", "feb", "mar", "apr", "may", "jun",
|
||||
"jul", "aug", "sep", "oct", "nov", "dec"
|
||||
};
|
||||
return monthNumber >= 1 && monthNumber <= 12 ? monthNames[monthNumber - 1] : "unknown";
|
||||
}
|
||||
|
||||
// Loads and updates the daily schedule
|
||||
void refreshDailySchedule() { loadDailySchedule(); }
|
||||
|
||||
// Returns the daily schedule in "ScheduleEntry" format
|
||||
const std::vector<ScheduleEntry>& getDailySchedule() const { return dailySchedule; }
|
||||
|
||||
// Prints the time, NOW.
|
||||
void printTimeNow(){
|
||||
LOG_INFO("Current Time: %s %s, %u - %02u:%02u:%02u\n",
|
||||
getMonth().c_str(), // Month as a string
|
||||
getDay().c_str(), // Day as a string
|
||||
getYear(), // Year as an integer
|
||||
getHour(), // Hour (24-hour format)
|
||||
getMinute(), // Minute
|
||||
getSecond()); // Second
|
||||
}
|
||||
|
||||
void tick(){
|
||||
updateTime();
|
||||
newDayCheck();
|
||||
}
|
||||
|
||||
void checkAndRunSchedule(Player & player) {
|
||||
LOG_DEBUG("Running daily schedule check");
|
||||
for (auto it = dailySchedule.begin(); it != dailySchedule.end(); ) {
|
||||
if (now.hour == it->hour && now.minute == it->minute) {
|
||||
LOG_DEBUG("Entry Exists, Calling program.");
|
||||
StaticJsonDocument<200> jsonDoc;
|
||||
jsonDoc["name"] = it->mel.c_str();
|
||||
jsonDoc["speed"] = it->speed;
|
||||
jsonDoc["duration"] = it->duration;
|
||||
jsonDoc["loop_dur"] = 0;
|
||||
jsonDoc["internal"] = 0;
|
||||
//LOG_INFO("Entry Found. Name: %s Speed: %d Duration: %d",it->mel.c_str(), it->speed, it->duration);
|
||||
if (!player.isPlaying){
|
||||
player.setMelodyAttributes(jsonDoc);
|
||||
player.loadMelodyInRAM(melody_steps);
|
||||
player.play();
|
||||
it = dailySchedule.erase(it);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG_DEBUG("Entry's time doesn't match. Skipping.");
|
||||
++it;
|
||||
}
|
||||
}
|
||||
bin_file.close();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
ADD MELODY:
|
||||
|
||||
{
|
||||
"cmd": "add_melody",
|
||||
"contents": {
|
||||
"url": "URL",
|
||||
"filename": "NAME.EXT"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SET RELAY TIMERS:
|
||||
|
||||
{
|
||||
"cmd": "set_relay_timers",
|
||||
"contents": {"b1":100, "b2":200}
|
||||
}
|
||||
|
||||
|
||||
START PLAYBACK:
|
||||
|
||||
{
|
||||
"cmd": "playback",
|
||||
"contents": {
|
||||
"action": "play"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STOP PLAYBACK:
|
||||
|
||||
{
|
||||
"cmd": "playback",
|
||||
"contents": {
|
||||
"action": "stop"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SET MELODY:
|
||||
|
||||
{
|
||||
"cmd": "set_melody",
|
||||
"contents": {
|
||||
"name": "esperinos",
|
||||
"id": "10",
|
||||
"duration": 5000,
|
||||
"infinite": true,
|
||||
"interval": 1000,
|
||||
"speed": 200,
|
||||
"loop_dur": 2000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LIST MELODIES
|
||||
|
||||
{
|
||||
"cmd": "list_melodies",
|
||||
}
|
||||
|
||||
|
||||
+41
-10
@@ -1,17 +1,48 @@
|
||||
const char* ssid = "SmartNet";
|
||||
const char* password = "smartpass";
|
||||
#pragma once
|
||||
|
||||
#define DEV_ID "PC201504180001"
|
||||
|
||||
// Network Config
|
||||
const char* ssid = "SmartNet"; //Not used with WiFi Manager
|
||||
const char* password = "smartpass"; //Not used with WiFi Manager
|
||||
const char* hostname = "ESP32_mqtt_test";
|
||||
|
||||
const IPAddress MQTT_HOST(10,98,20,10);
|
||||
const int MQTT_PORT = 1883;
|
||||
|
||||
#define MQTT_USER "esp32_vesper"
|
||||
#define MQTT_PASS "vesper"
|
||||
|
||||
IPAddress ip(10, 98, 30, 150);
|
||||
IPAddress gateway(10, 98, 30, 1);
|
||||
IPAddress subnet(255, 255, 255, 0);
|
||||
String ap_ssid = String("BellSystems - ") + DEV_ID;
|
||||
String ap_pass = "password";
|
||||
|
||||
#define DEV_ID "id-96638646"
|
||||
// Version Controll Settings
|
||||
const char* versionUrl = "http://10.98.20.10:85/version.txt";
|
||||
const char* firmwareUrl = "http://10.98.20.10:85/firmware.bin";
|
||||
const float currentVersion = 1.1;
|
||||
|
||||
// NTP Config
|
||||
const char* ntpServer = "pool.ntp.org";
|
||||
const long gmtOffset_sec = 7200;
|
||||
const int daylightOffset_sec = 3600;
|
||||
|
||||
// MQTT Config
|
||||
const IPAddress MQTT_HOST(10,98,20,10);
|
||||
const int MQTT_PORT = 1883;
|
||||
#define MQTT_USER "esp32_vesper"
|
||||
#define MQTT_PASS "vesper"
|
||||
|
||||
// Hardware Configuration
|
||||
#define PCF8574_ADDR 0x24
|
||||
|
||||
|
||||
// SPI W5500 ETHERNET SETUP
|
||||
#define USE_TWO_ETH_PORTS 0
|
||||
|
||||
#ifndef ETH_PHY_CS
|
||||
#define ETH_PHY_TYPE ETH_PHY_W5500
|
||||
#define ETH_PHY_ADDR 1
|
||||
#define ETH_PHY_CS 5
|
||||
#define ETH_PHY_IRQ -1
|
||||
#define ETH_PHY_RST -1
|
||||
#endif
|
||||
// SPI pins
|
||||
#define ETH_SPI_SCK 18
|
||||
#define ETH_SPI_MISO 19
|
||||
#define ETH_SPI_MOSI 23
|
||||
|
||||
+369
-50
@@ -7,10 +7,8 @@ void saveRelayTimings();
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
|
||||
|
||||
// Sets Incoming Relay Durations to RAM and then call funtion to save them to file.
|
||||
void updateRelayTimings(JsonDocument doc) {
|
||||
void updateRelayTimings(JsonVariant doc) {
|
||||
// Iterate through the relays in the JSON payload
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
String key = String("b") + (i + 1); // Generate "b1", "b2", ...
|
||||
@@ -25,16 +23,33 @@ void updateRelayTimings(JsonDocument doc) {
|
||||
LOG_INFO("Updated Relay Timings.")
|
||||
}
|
||||
|
||||
// Save file "fileName" with data: "data"
|
||||
void savefile(const char* fileName, const char* data) {
|
||||
File file = SPIFFS.open(fileName, "w");
|
||||
if (!file) {
|
||||
LOG_ERROR("Failed to open file!");
|
||||
// Save file "filename" with data: "data" to the "dirPath" directory of the SD card
|
||||
void saveFileToSD(const char* dirPath, const char* filename, const char* data) {
|
||||
// Initialize SD (if not already done)
|
||||
if (!SD.begin(SD_CS)) {
|
||||
LOG_ERROR("SD Card not initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure directory exists
|
||||
if (!SD.exists(dirPath)) {
|
||||
SD.mkdir(dirPath);
|
||||
}
|
||||
|
||||
// Build full path
|
||||
String fullPath = String(dirPath);
|
||||
if (!fullPath.endsWith("/")) fullPath += "/";
|
||||
fullPath += filename;
|
||||
|
||||
File file = SD.open(fullPath.c_str(), FILE_WRITE);
|
||||
if (!file) {
|
||||
LOG_ERROR("Failed to open file: %s", fullPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
file.print(data);
|
||||
file.close();
|
||||
LOG_INFO("File %s saved successfully.\n", fileName);
|
||||
LOG_INFO("File %s saved successfully.\n", fullPath.c_str());
|
||||
}
|
||||
|
||||
// Saves Relay Durations from RAM, into a file
|
||||
@@ -54,41 +69,30 @@ void saveRelayTimings() {
|
||||
return;
|
||||
}
|
||||
|
||||
const char * fileName = "/settings/relayTimings.json";
|
||||
savefile(fileName, buffer);
|
||||
|
||||
// // Open the file for writing
|
||||
// File file = SPIFFS.open("/settings/relayTimings.json", "w");
|
||||
// if (!file) {
|
||||
// Serial.println("Failed to open file for writing");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Serialize JSON to the file
|
||||
// if (serializeJson(doc, file) == 0) {
|
||||
// Serial.println("Failed to write JSON to file");
|
||||
// } else {
|
||||
// Serial.println("Relay timings saved successfully");
|
||||
// }
|
||||
//
|
||||
// file.close();
|
||||
const char * path = "/settings";
|
||||
const char * filename = "relayTimings.json";
|
||||
saveFileToSD(path, filename, buffer);
|
||||
}
|
||||
|
||||
// Loads Relay Durations from file into RAM (called during boot)
|
||||
void loadRelayTimings() {
|
||||
// Open the file for reading
|
||||
File file = SPIFFS.open("/settings/relayTimings.json", "r");
|
||||
if (!file) {
|
||||
LOG_ERROR("Settings file not found. Using default relay timings.");
|
||||
|
||||
if (!SD.begin(SD_CS)) {
|
||||
LOG_ERROR("SD Card not initialized. Using default relay timings.");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = SD.open("/settings/relayTimings.json", FILE_READ);
|
||||
if (!file) {
|
||||
LOG_ERROR("Settings file not found on SD. Using default relay timings.");
|
||||
return;
|
||||
}
|
||||
// Parse the JSON file
|
||||
StaticJsonDocument<512> doc; // Adjust size if needed
|
||||
DeserializationError error = deserializeJson(doc, file);
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse settings file. Using default relay timings.");
|
||||
file.close();
|
||||
if (error) {
|
||||
LOG_ERROR("Failed to parse settings from SD. Using default relay timings.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,28 +105,343 @@ void loadRelayTimings() {
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
//
|
||||
void updateSchedule(JsonDocument doc) {
|
||||
const char* fileName = doc["file"];
|
||||
// Function to sync time with NTP server and update RTC
|
||||
void syncTimeWithNTP() {
|
||||
// Connect to Wi-Fi if not already connected
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
LOG_DEBUG("Connecting to Wi-Fi...");
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
LOG_DEBUG(".");
|
||||
}
|
||||
LOG_DEBUG("\nWi-Fi connected!");
|
||||
}
|
||||
|
||||
// Ensure fileName exists and is valid
|
||||
if (!fileName || strlen(fileName) == 0) {
|
||||
LOG_ERROR("Invalid JSON payload: Missing or invalid 'file' field");
|
||||
// Configure NTP
|
||||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||
|
||||
// Sync time from NTP server
|
||||
LOG_DEBUG("Syncing time with NTP server...");
|
||||
struct tm timeInfo;
|
||||
if (!getLocalTime(&timeInfo)) {
|
||||
LOG_DEBUG("Failed to obtain time from NTP server!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Serialize the "data" object into a string
|
||||
String dataString;
|
||||
serializeJson(doc["data"], dataString); // Converts the "data" object to a JSON string
|
||||
// Update RTC with synchronized time
|
||||
rtc.adjust(DateTime(timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
|
||||
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec));
|
||||
|
||||
if (dataString.length() > 0) {
|
||||
savefile(fileName, dataString.c_str());
|
||||
LOG_INFO("File '%s' updated successfully.\n", fileName);
|
||||
} else {
|
||||
LOG_DEBUG("Invalid JSON payload: Unable to serialize 'data'");
|
||||
}
|
||||
timekeeper.refreshDailySchedule();
|
||||
// Log synchronized time
|
||||
LOG_INFO("Time synced with NTP server.");
|
||||
LOG_DEBUG("Synced time: %02d:%02d:%02d, %02d/%02d/%04d",
|
||||
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec,
|
||||
timeInfo.tm_mday, timeInfo.tm_mon + 1, timeInfo.tm_year + 1900);
|
||||
}
|
||||
|
||||
// Call this function with the Firebase URL and desired local filename
|
||||
bool downloadFileToSD(const String& url, const String& directory, const String& filename) {
|
||||
LOG_INFO("HTTP Starting download...");
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode != HTTP_CODE_OK) {
|
||||
LOG_ERROR("(HTTP) GET failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SD.begin(SD_CS)) {
|
||||
LOG_ERROR("SD Card init failed!");
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the directory ends with '/'
|
||||
String dirPath = directory;
|
||||
if (!dirPath.endsWith("/")) dirPath += "/";
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
SD.mkdir(dirPath.c_str());
|
||||
|
||||
String fullPath = dirPath + filename;
|
||||
|
||||
File file = SD.open(fullPath.c_str(), FILE_WRITE);
|
||||
if (!file) {
|
||||
LOG_ERROR("SD Failed to open file for writing: %s", fullPath.c_str());
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
WiFiClient* stream = http.getStreamPtr();
|
||||
uint8_t buffer[1024];
|
||||
int bytesRead;
|
||||
|
||||
while (http.connected() && (bytesRead = stream->readBytes(buffer, sizeof(buffer))) > 0) {
|
||||
file.write(buffer, bytesRead);
|
||||
}
|
||||
|
||||
file.close();
|
||||
http.end();
|
||||
LOG_INFO("HTTP Download complete, file saved to: %s", fullPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Returns the list of melodies (the filenames) currently inside the SD Card.
|
||||
String listFilesAsJson(const char* dirPath) {
|
||||
if (!SD.begin(SD_CS)) {
|
||||
LOG_ERROR("SD init failed");
|
||||
return "{}";
|
||||
}
|
||||
|
||||
File dir = SD.open(dirPath);
|
||||
if (!dir || !dir.isDirectory()) {
|
||||
LOG_ERROR("Directory not found");
|
||||
return "{}";
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(1024); // Adjust size if needed
|
||||
JsonArray fileList = doc.createNestedArray("files");
|
||||
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
if (!file.isDirectory()) {
|
||||
fileList.add(file.name());
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
|
||||
String json;
|
||||
serializeJson(doc, json);
|
||||
return json;
|
||||
}
|
||||
|
||||
// Prints the Steps of a Melody from a file using its filename
|
||||
void printMelodyFile(const String& filename) {
|
||||
if (!SD.begin(SD_CS)) {
|
||||
LOG_ERROR("SD Card not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = SD.open("/melodies/" + filename, FILE_READ);
|
||||
if (!file) {
|
||||
Serial.println("Failed to open Melody file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("---- Contents of %s ----\n", filename.c_str());
|
||||
|
||||
uint16_t step;
|
||||
int index = 0;
|
||||
|
||||
while (file.available() >= 2) {
|
||||
uint8_t low = file.read();
|
||||
uint8_t high = file.read();
|
||||
step = (high << 8) | low;
|
||||
Serial.printf("Step %5d: 0x%04X (%d)\n", index++, step, step);
|
||||
}
|
||||
|
||||
file.close();
|
||||
Serial.println("---- End of File ----");
|
||||
}
|
||||
|
||||
// Prints the contents of a Text file using its filename
|
||||
void printFileAsText(const String& path, const String& filename) {
|
||||
if (!SD.begin(SD_CS)) {
|
||||
LOG_ERROR("SD Card not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
String fullPath = path;
|
||||
if (!fullPath.endsWith("/")) fullPath += "/";
|
||||
fullPath += filename;
|
||||
|
||||
File file = SD.open(fullPath, FILE_READ);
|
||||
if (!file) {
|
||||
Serial.println("Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("---- Contents of %s ----\n", filename.c_str());
|
||||
|
||||
while (file.available()) {
|
||||
String line = file.readStringUntil('\n');
|
||||
Serial.println(line);
|
||||
}
|
||||
|
||||
file.close();
|
||||
Serial.println("---- End of File ----");
|
||||
}
|
||||
|
||||
// Downloads a new melody from HTTP
|
||||
void addMelody(JsonVariant doc) {
|
||||
|
||||
LOG_INFO("Trying Saving...");
|
||||
const char* url = doc["url"];
|
||||
const char* filename = doc["filename"];
|
||||
downloadFileToSD(url, "/melodies", filename);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Checks the onboard SD Card for new firmware
|
||||
void checkFirmwareUpdate() {
|
||||
if (!SD.begin(SD_CS)) {
|
||||
Serial.println("SD init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
File updateBin = SD.open("/firmware/update.bin");
|
||||
if (!updateBin) {
|
||||
Serial.println("No update.bin found");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t updateSize = updateBin.size();
|
||||
if (updateSize == 0) {
|
||||
Serial.println("Empty update file");
|
||||
updateBin.close();
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Starting firmware update...");
|
||||
|
||||
if (Update.begin(updateSize)) {
|
||||
size_t written = Update.writeStream(updateBin);
|
||||
if (written == updateSize) {
|
||||
Serial.println("Update written successfully");
|
||||
} else {
|
||||
Serial.printf("Written only %d/%d bytes\n", written, updateSize);
|
||||
}
|
||||
|
||||
if (Update.end()) {
|
||||
Serial.println("Update finished!");
|
||||
if (Update.isFinished()) {
|
||||
Serial.println("Update complete. Rebooting...");
|
||||
updateBin.close();
|
||||
SD.remove("/firmware/update.bin"); // optional cleanup
|
||||
ESP.restart();
|
||||
} else {
|
||||
Serial.println("Update not complete");
|
||||
}
|
||||
} else {
|
||||
Serial.printf("Update error: %s\n", Update.errorString());
|
||||
}
|
||||
} else {
|
||||
Serial.println("Not enough space to begin update");
|
||||
}
|
||||
|
||||
updateBin.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// UNSUSED FUNCTIONS.
|
||||
|
||||
// void startConfigPortal() {
|
||||
// WiFi.mode(WIFI_AP);
|
||||
// WiFi.softAP("Device_Config", "12345678");
|
||||
// Serial.println("AP mode started. Connect to 'Device_Config'.");
|
||||
|
||||
// // Serve the configuration page
|
||||
// server.on("/", HTTP_GET, []() {
|
||||
// server.send(200, "text/html", generateConfigPageHTML());
|
||||
// });
|
||||
|
||||
// // Handle form submission
|
||||
// server.on("/save", HTTP_POST, []() {
|
||||
// ssid = server.arg("ssid");
|
||||
// password = server.arg("password");
|
||||
// mqttHost.fromString(server.arg("mqttHost"));
|
||||
// mqttUser = server.arg("mqttUser");
|
||||
// mqttPassword = server.arg("mqttPassword");
|
||||
|
||||
// saveSettings(); // Save new settings to SPIFFS
|
||||
// server.send(200, "text/plain", "Settings saved! Rebooting...");
|
||||
// delay(1000);
|
||||
// ESP.restart();
|
||||
// });
|
||||
|
||||
// server.begin();
|
||||
// }
|
||||
|
||||
// // Save settings to SPIFFS
|
||||
// void saveSettings() {
|
||||
// StaticJsonDocument<512> doc;
|
||||
// doc["ssid"] = ssid;
|
||||
// doc["password"] = password;
|
||||
// doc["mqttHost"] = mqttHost.toString();
|
||||
// doc["mqttUser"] = mqttUser;
|
||||
// doc["mqttPassword"] = mqttPassword;
|
||||
|
||||
// File configFile = SPIFFS.open(CONFIG_FILE, "w");
|
||||
// if (!configFile) {
|
||||
// Serial.println("Failed to open config file for writing.");
|
||||
// return;
|
||||
// }
|
||||
// serializeJson(doc, configFile);
|
||||
// configFile.close();
|
||||
// Serial.println("Settings saved to SPIFFS.");
|
||||
// }
|
||||
|
||||
// // Load settings from SPIFFS
|
||||
// void loadSettings() {
|
||||
// if (!SPIFFS.exists(CONFIG_FILE)) {
|
||||
// Serial.println("Config file not found. Using defaults.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// File configFile = SPIFFS.open(CONFIG_FILE, "r");
|
||||
// if (!configFile) {
|
||||
// Serial.println("Failed to open config file.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// StaticJsonDocument<512> doc;
|
||||
// DeserializationError error = deserializeJson(doc, configFile);
|
||||
// if (error) {
|
||||
// Serial.println("Failed to parse config file.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// ssid = doc["ssid"].as<String>();
|
||||
// password = doc["password"].as<String>();
|
||||
// mqttHost.fromString(doc["mqttHost"].as<String>());
|
||||
// mqttUser = doc["mqttUser"].as<String>();
|
||||
// mqttPassword = doc["mqttPassword"].as<String>();
|
||||
|
||||
// configFile.close();
|
||||
// Serial.println("Settings loaded from SPIFFS.");
|
||||
// }
|
||||
|
||||
// // Generate HTML page for configuration
|
||||
// String generateConfigPageHTML() {
|
||||
// String page = R"rawliteral(
|
||||
// <!DOCTYPE html>
|
||||
// <html>
|
||||
// <body>
|
||||
// <h2>Device Configuration</h2>
|
||||
// <form action="/save" method="POST">
|
||||
// WiFi SSID: <input type="text" name="ssid" value=")rawliteral" +
|
||||
// ssid + R"rawliteral("><br>
|
||||
// WiFi Password: <input type="password" name="password" value=")rawliteral" +
|
||||
// password + R"rawliteral("><br>
|
||||
// MQTT Host: <input type="text" name="mqttHost" value=")rawliteral" +
|
||||
// mqttHost.toString() + R"rawliteral("><br>
|
||||
// MQTT Username: <input type="text" name="mqttUser" value=")rawliteral" +
|
||||
// mqttUser + R"rawliteral("><br>
|
||||
// MQTT Password: <input type="password" name="mqttPassword" value=")rawliteral" +
|
||||
// mqttPassword + R"rawliteral("><br>
|
||||
// <input type="submit" value="Save">
|
||||
// </form>
|
||||
// </body>
|
||||
// </html>
|
||||
// )rawliteral";
|
||||
// return page;
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
void checkForUpdates();
|
||||
void performOTA();
|
||||
|
||||
void checkForUpdates() {
|
||||
Serial.println("Checking for firmware updates...");
|
||||
|
||||
// Step 1: Check the current version on the server
|
||||
HTTPClient http;
|
||||
http.begin(versionUrl);
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
String newVersionStr = http.getString();
|
||||
float newVersion = newVersionStr.toFloat();
|
||||
|
||||
Serial.printf("Current version: %.1f, Available version: %.1f\n", currentVersion, newVersion);
|
||||
|
||||
// Step 2: Compare the version
|
||||
if (newVersion > currentVersion) {
|
||||
Serial.println("New version available. Starting update...");
|
||||
performOTA(); // Perform the OTA update if a new version is found
|
||||
} else {
|
||||
Serial.println("No new version available.");
|
||||
}
|
||||
} else {
|
||||
Serial.printf("Failed to retrieve version. HTTP error code: %d\n", httpCode);
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
|
||||
void performOTA() {
|
||||
HTTPClient http;
|
||||
http.begin(firmwareUrl);
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
int contentLength = http.getSize();
|
||||
if (contentLength > 0) {
|
||||
bool canBegin = Update.begin(contentLength);
|
||||
if (canBegin) {
|
||||
Serial.println("Starting OTA update...");
|
||||
WiFiClient *client = http.getStreamPtr();
|
||||
size_t written = Update.writeStream(*client);
|
||||
if (written == contentLength) {
|
||||
Serial.println("Update complete");
|
||||
if (Update.end()) {
|
||||
Serial.println("Update successfully finished. Rebooting...");
|
||||
ESP.restart(); // Reboot to apply the update
|
||||
} else {
|
||||
Serial.printf("Update failed: %s\n", Update.errorString());
|
||||
}
|
||||
} else {
|
||||
Serial.println("Update failed: Written size mismatch.");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Not enough space for update.");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Firmware file is empty.");
|
||||
}
|
||||
} else {
|
||||
Serial.printf("Firmware HTTP error code: %d\n", httpCode);
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
+83
-43
@@ -1,52 +1,87 @@
|
||||
/*
|
||||
|
||||
TODO List:
|
||||
Done Features:
|
||||
|
||||
- Add OTA Updates
|
||||
- Add reset to Factory Defaults
|
||||
- Initiate General Structure
|
||||
- Add WiFi Support
|
||||
- Add MQTT Support both for Subscribing and Publishing
|
||||
- Add JSON support to handle MQTT messaging
|
||||
- Add File Handling
|
||||
- Add Melody Class with functions to Play/Pause/Stop etc.
|
||||
- Add Main BellEngine
|
||||
- Add custom Relay Timings (saved on-board)
|
||||
- Add RTC support
|
||||
- Add Timekeeper class, with functions to track time and call schedules
|
||||
- Add OTA Update Functionality
|
||||
- Add global logger with Mode Selection (None, Error, Warning, Info, Debug)
|
||||
- Add Captive Portal / WiFi HotSpot
|
||||
- Add manual Sync-Time
|
||||
- Add NTP Time Sync
|
||||
|
||||
ToDo Features:
|
||||
|
||||
- Add reset to Factory Defaults button
|
||||
- Add manual Sync-Time (for No-Connectivity Setups)
|
||||
- Add the ability to report the list of melodies
|
||||
- Add the ability to report a month's ScheduleEntry
|
||||
- Add the ability to report the free space in SPIFFS.
|
||||
- Add global logger
|
||||
- Add
|
||||
- Add Bluetooth support
|
||||
- Add WiFi Direct AP Support
|
||||
- Add PCB Temperature Sensor
|
||||
- Counters and Statistics:
|
||||
- Counter for each bell (counts total times the bell ringed)
|
||||
- Counter per bell, beats/minute for reliability and thermal protection. Warranty Void scenario.
|
||||
- Counter per playback, to figure out which melody is the most played.
|
||||
- Counter of items per Scheduler
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "logging.hpp"
|
||||
|
||||
#include <SD.h>
|
||||
#include <FS.h>
|
||||
#include <ETH.h>
|
||||
#include <SPI.h>
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <Update.h>
|
||||
#include <AsyncMqttClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <string>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_PCF8574.h>
|
||||
#include "RTClib.h"
|
||||
#include <WebServer.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <WiFiManager.h>
|
||||
|
||||
|
||||
// Hardware Constructors:
|
||||
Adafruit_PCF8574 relays;
|
||||
RTC_DS1307 rtc;
|
||||
|
||||
// SD Card Chip Select:
|
||||
#define SD_CS 5
|
||||
|
||||
// Include Classes
|
||||
#include "classes.hpp"
|
||||
|
||||
// Class Constructors
|
||||
AsyncMqttClient mqttClient;
|
||||
Player player;
|
||||
TimeKeeper timekeeper;
|
||||
std::vector<uint16_t> melody_steps; // holds the steps of the melody. Should move into bell Engine.
|
||||
AsyncWebServer server(80);
|
||||
|
||||
AsyncWebSocket ws("/ws");
|
||||
|
||||
#include "config.h"
|
||||
#include "ota.hpp"
|
||||
#include "functions.hpp"
|
||||
#include "MQTT_Message_Handling.hpp"
|
||||
#include "MQTT_WiFi_Utilities.hpp"
|
||||
#include "PlaybackControls.hpp"
|
||||
#include "bellEngine.hpp"
|
||||
#include "Scheduler.hpp"
|
||||
|
||||
TaskHandle_t bellEngineHandle = NULL;
|
||||
TimerHandle_t schedulerTimer;
|
||||
@@ -57,64 +92,69 @@ void setup()
|
||||
{
|
||||
// Initialize Serial Communications & I2C Bus (for debugging)
|
||||
Serial.begin(115200);
|
||||
Wire.begin(4,15);
|
||||
SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI);
|
||||
delay(50);
|
||||
|
||||
// Initialize PCF8574
|
||||
Wire.begin(4,15);
|
||||
// Initialize PCF8574 and Relays
|
||||
relays.begin(PCF8574_ADDR, &Wire);
|
||||
// Initialize Relays
|
||||
for (uint8_t p=0; p<6; p++){
|
||||
relays.pinMode(p, OUTPUT);
|
||||
relays.digitalWrite(p, HIGH);
|
||||
}
|
||||
// Initialize SPIFFS
|
||||
if (!SPIFFS.begin(true)) { // 'true' means format SPIFFS if initialization fails
|
||||
LOG_ERROR("Failed to mount SPIFFS");
|
||||
while(true) delay(10);
|
||||
|
||||
|
||||
// Initialize SD Card
|
||||
if (!SD.begin(SD_CS)) {
|
||||
Serial.println("SD card not found. Using defaults.");
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
LOG_INFO("SPIFFS mounted successfully");
|
||||
delay(50);
|
||||
|
||||
// Initialize RTC
|
||||
if (!rtc.begin()) {
|
||||
Serial.println("Couldn't find RTC");
|
||||
LOG_ERROR("Couldn't find RTC");
|
||||
while(true) delay(10);
|
||||
}
|
||||
|
||||
if (! rtc.isrunning()) {
|
||||
LOG_INFO("RTC is NOT running, let's set the time!");
|
||||
// When time needs to be set on a new device, or after a power loss, the
|
||||
// following line sets the RTC to the date & time this sketch was compiled
|
||||
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
|
||||
// This line sets the RTC with an explicit date & time, for example to set
|
||||
// January 21, 2014 at 3am you would call:
|
||||
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
|
||||
// Initialize Networking and MQTT
|
||||
Network.onEvent(NetworkEvent);
|
||||
ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI);
|
||||
InitMqtt();
|
||||
WiFiManager wm;
|
||||
//wm.resetSettings(); // Only for Debugging.
|
||||
bool res;
|
||||
res = wm.autoConnect(ap_ssid.c_str(),ap_pass.c_str());
|
||||
if(!res) {
|
||||
LOG_ERROR("Failed to connect to WiFi");
|
||||
}
|
||||
else {
|
||||
LOG_INFO("Connected to WiFi");
|
||||
}
|
||||
|
||||
delay(100);
|
||||
|
||||
// Initialize WiFi and MQTT
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
InitMqtt();
|
||||
ConnectWiFi_STA();
|
||||
delay(1000);
|
||||
checkForUpdates(); // checks for updates online
|
||||
syncTimeWithNTP(); // syncs time from NTP Server
|
||||
|
||||
delay(100);
|
||||
|
||||
// WebSocket setup
|
||||
ws.onEvent(onWebSocketEvent);
|
||||
server.addHandler(&ws);
|
||||
// Start the server
|
||||
server.begin();
|
||||
|
||||
// Tasks and Timers
|
||||
xTaskCreatePinnedToCore(bellEngine,"bellEngine", 8192, NULL, 1, &bellEngineHandle, 1);
|
||||
xTaskCreatePinnedToCore(durationTimer, "durationTimer", 8192, NULL, 2, NULL, 1);
|
||||
xTaskCreatePinnedToCore(relayControlTask, "Relay Control", 2048, NULL, 2, NULL, 1);
|
||||
|
||||
schedulerTimer = xTimerCreate("Timer",pdMS_TO_TICKS(10000),pdTRUE,(void*)0,reinterpret_cast<TimerCallbackFunction_t>(schedule_timer));
|
||||
|
||||
if (schedulerTimer != NULL) {
|
||||
xTimerStart(schedulerTimer, 0);
|
||||
} else {
|
||||
LOG_ERROR("Failed to create timer!");
|
||||
}
|
||||
|
||||
timekeeper.refreshDailySchedule();
|
||||
loadRelayTimings();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user