diff --git a/.gitignore b/.gitignore
index 5c228a4..a4a37ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,6 @@
.vscode/ipch
.vs/
.vscode/
-.vscode/settings.json
\ No newline at end of file
+.vscode/settings.json
+firmware/
+release/
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 2975662..ee32b37 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -73,5 +73,6 @@
"C_Cpp_Runner.useLeakSanitizer": false,
"C_Cpp_Runner.showCompilationTime": false,
"C_Cpp_Runner.useLinkTimeOptimization": false,
- "C_Cpp_Runner.msvcSecureNoWarnings": false
+ "C_Cpp_Runner.msvcSecureNoWarnings": false,
+ "cmake.sourceDirectory": "D:/Git/iot-firmware/.pio/libdeps/full/Adafruit BusIO"
}
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..40b69c7
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,20 @@
+pipeline {
+ agent any
+
+ stages {
+ stage('Build') {
+ steps {
+ git branch: 'ise', url: 'https://git.siwatsystem.com/ise-senior-iot/iot-firmware.git'
+ sh 'export PLATFORMIO_PATH=/root/.platformio/penv/bin/platformio'
+ sh '/usr/bin/python3 gen_release.py'
+ stash includes: 'release/**/*', name: 'release_binaries'
+ }
+ }
+ stage('Publish') {
+ steps {
+ unstash 'release_binaries'
+ archiveArtifacts artifacts: 'release/**/*', fingerprint: true
+ }
+ }
+ }
+}
diff --git a/gen_release.py b/gen_release.py
new file mode 100644
index 0000000..2c07d5e
--- /dev/null
+++ b/gen_release.py
@@ -0,0 +1,115 @@
+import os
+import shutil
+import subprocess
+import sys
+import subprocess
+import os
+import shutil
+import subprocess
+import sys
+import platform
+import re
+import configparser
+from time import sleep as delay
+
+
+# Get the current directory
+current_dir = os.path.dirname(os.path.abspath(__file__))
+
+# Define the path to the firmware folder
+firmware_folder = os.path.join(current_dir, 'firmware')
+
+# Create the firmware folder if it does not exist
+if not os.path.exists(firmware_folder):
+ os.makedirs(firmware_folder)
+
+# Define the path to the release folder
+release_folder = os.path.join(current_dir, 'release')
+
+# Get the platformio path from environment variable
+platformio_path = os.environ.get('PLATFORMIO_PATH')
+# If the environment variable is not set, use the default path
+if platformio_path is None:
+ if platform.system() == 'Darwin':
+ platformio_path = os.path.expanduser('~/.platformio/penv/bin/platformio')
+ elif platform.system() == 'Windows':
+ platformio_path = os.path.expanduser('~/.platformio/penv/Scripts/platformio.exe')
+ elif platform.system() == 'Linux':
+ platformio_path = os.path.expanduser('~/.platformio/penv/bin/platformio')
+
+if os.path.exists(release_folder):
+ # If the release folder exists, delete it
+ shutil.rmtree(release_folder)
+os.makedirs(release_folder)
+
+# Get the current Git branch name
+git_branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).decode().strip()
+commit_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode().strip()[:10]
+
+# If arguments are supplied, build the environments that match the arguments
+if len(sys.argv) > 1:
+ environments = sys.argv[1:]
+
+# If no argument are supplied, build all environments listed in platformio.ini
+else:
+ environments = []
+ with open(os.path.join(current_dir, 'platformio.ini')) as f:
+
+ # Iterate over the lines in platformio.ini
+ for line in f.readlines():
+
+ # Check if the line contains the string "env:"
+ if '[env:' in line:
+
+ # Extract the environment using regular expressions
+ environment = re.search(r'\[env:(.*?)\]', line).group(1)
+
+ # Add the environment to the list of environments
+ environments.append(environment)
+
+# Remove old platformio.ini file from firmware folder if it exists
+if os.path.isfile(os.path.join(firmware_folder, 'platformio.ini')):
+ os.remove(os.path.join(firmware_folder, 'platformio.ini'))
+
+# Copy the platformio.ini file to the firmware folder
+shutil.copyfile(os.path.join(current_dir, 'platformio.ini'), os.path.join(firmware_folder, 'platformio.ini'))
+
+# Check that the file is copied correctly
+if not os.path.isfile(os.path.join(firmware_folder, 'platformio.ini')):
+ raise Exception('platformio.ini file not copied correctly')
+
+# Read the platformio.ini file
+config = configparser.ConfigParser()
+config.read(os.path.join(firmware_folder, 'platformio.ini'))
+
+# Add firmware version to build_flags in platformio.ini
+for environment in environments:
+ if 'build_flags' not in config[f'env:{environment}']:
+ config[f'env:{environment}']['build_flags'] = f'-DFW_VERSION=\\"{git_branch}_{environment}_{commit_hash}\\"'
+ else:
+ config[f'env:{environment}']['build_flags'] = config[f'env:{environment}']['build_flags'] + f' -DFW_VERSION=\\"{git_branch}_{environment}_{commit_hash}\\"'
+
+# Write the platformio.ini file
+with open(os.path.join(firmware_folder, 'platformio.ini'), 'w') as configfile:
+ config.write(configfile)
+
+# if argument is not supplied, build all environments listed in platformio.ini
+if len(sys.argv) == 1:
+ subprocess.run([f'{platformio_path}', 'run','-c',f'{firmware_folder}/platformio.ini'], cwd=current_dir)
+
+for environment in environments:
+ if(len(sys.argv) > 1):
+ subprocess.run([f'{platformio_path}', 'run', '-e', environment,'-c',f'{firmware_folder}/platformio.ini'], cwd=current_dir)
+
+ # Iterate over the subfolders in the firmware folder
+ for subfolder in os.listdir(firmware_folder):
+ subfolder_path = os.path.join(firmware_folder, subfolder)
+
+ # Check if the subfolder matches the environment argument
+ if subfolder == environment:
+ # Check if the subfolder contains a firmware.bin file
+ firmware_file = os.path.join(subfolder_path, 'firmware.bin')
+ if os.path.isfile(firmware_file):
+ # Move the firmware.bin file to the release folder with the Git branch name and commit hash appended
+ new_file_name = os.path.join(release_folder, f"{git_branch}_{subfolder}_{commit_hash}.bin")
+ shutil.move(firmware_file, new_file_name)
\ No newline at end of file
diff --git a/ise_display/Images/Rev1/Off-IC.png b/ise_display/Images/Rev1/Off-IC.png
new file mode 100644
index 0000000..eab181e
Binary files /dev/null and b/ise_display/Images/Rev1/Off-IC.png differ
diff --git a/ise_display/ise_display.HMI b/ise_display/ise_display.HMI
index a15c227..5f8c0a1 100644
Binary files a/ise_display/ise_display.HMI and b/ise_display/ise_display.HMI differ
diff --git a/ise_display/ise_display_test2.HMI b/ise_display/ise_display_test2.HMI
new file mode 100644
index 0000000..e6dcbeb
Binary files /dev/null and b/ise_display/ise_display_test2.HMI differ
diff --git a/platformio.ini b/platformio.ini
index 1995297..da29e98 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -8,7 +8,153 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
-[env:wt32-eth01]
+[platformio]
+build_dir = firmware
+
+[env:full]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_INTERNAL_LCD -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE -DENABLE_ANALOG_MODULE -DENABLE_WEBUI
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:lcd_climate]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_INTERNAL_LCD -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:webui]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_WEBUI
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+
+[env:climate_webui]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE -DENABLE_WEBUI
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:lcd_webui]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_INTERNAL_LCD -DENABLE_WEBUI
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:ir_climate_analog_webui]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE -DENABLE_ANALOG_MODULE -DENABLE_WEBUI
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:lcd_analog]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_INTERNAL_LCD -DENABLE_ANALOG_MODULE
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:lcd]
+platform = espressif32
+board = wt32-eth01
+framework = arduino
+board_build.f_cpu = 240000000L
+build_flags = -DENABLE_INTERNAL_LCD
+lib_deps = siwats/ESPMegaPROR3@^1.3.0
+ knolleary/PubSubClient@^2.8
+ ivanseidel/ArduinoThread@^2.1.1
+ arduino-libraries/Arduino_BuiltIn@^1.0.0
+ dersimn/PubSubClientTools@^0.6
+ z3t0/IRremote@^4.2.0
+ robtillaart/DHTNEW@^0.4.18
+ seithan/Easy Nextion Library@^1.0.6
+ robtillaart/FRAM_I2C@^0.6.1
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
+monitor_speed = 115200
+
+[env:minimal]
platform = espressif32
board = wt32-eth01
framework = arduino
@@ -22,5 +168,4 @@ lib_deps = siwats/ESPMegaPROR3@^1.3.0
robtillaart/DHTNEW@^0.4.18
seithan/Easy Nextion Library@^1.0.6
robtillaart/FRAM_I2C@^0.6.1
- esphome/ESPAsyncWebServer-esphome@^3.1.0
-monitor_speed = 115200
\ No newline at end of file
+ esphome/ESPAsyncWebServer-esphome@^3.1.0
\ No newline at end of file
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..b0a4f7e
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,35 @@
+# IoT Core OS V3
+This is an OS for the ESPMega PRO R3 Programable Logic Controller
+
+## **Compatibility**
+1. **CPU**
+ - ESPMega PRO R3.0a/b
+ - ESPMega PRO R3.1a
+ - ESPMega PRO R3.2a/b/c
+2. **CPU Add-ons**
+ - ESPMega PRO Internal Display Module
+ - ESPMega PRO External Touch Display Module
+3. **Add-on Cards**
+ - ESPMega I/O Analog Expansion Card
+ - ESPMega I/O IR Expansion Kit
+ - ESPMega I/O Card Hub
+ - ESPMega I/O UART Multiplexer [WIP]
+ - ESPMega I/O Digital Expansion Card [WIP]
+
+## Features
+- Internal Touch Display support for diagnostics and configuration
+- WebUI for Configuration and OTA Update
+- Allowing for reading and writing to registers from MQTT
+- Provides abstraction layer to the MQTT protocol and internal components
+
+## User Code and 3rd Party Extension
+This OS allows the user to write custom program for the device to run in the OS
+### *usercode.hpp* and *user_code.cpp*
+### I/O Abstraction Layer
+### MQTT Abstraction Layer
+### RTC and Clock Abstraction Layer
+### Persistent Storage Abstraction Layer
+### Climate Abstraction Layer
+### Energy Monitoring Abstraction Layer
+### Timer Abstraction Layer
+### LCD Abstraction Layer
diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp
index af1b163..0472888 100644
--- a/src/espmega_iot_core.cpp
+++ b/src/espmega_iot_core.cpp
@@ -32,16 +32,22 @@ WebServer otaserver(80);
#endif
bool standalone = true;
char MQTT_BASE_TOPIC[20];
+char AVAILABILITY_TOPIC[40];
uint8_t base_topic_length = 0;
char STATE_REQUEST_TOPIC[40];
bool MQTT_USE_AUTH = false;
char MQTT_USERNAME[32];
char MQTT_PASSWORD[32];
+#ifdef ENABLE_WEBUI
+char WEBUI_USERNAME[32];
+char WEBUI_PASSWORD[32];
+#endif
uint8_t utc_offset = 7;
#ifdef ENABLE_CLIMATE_MODULE
float current_room_temp = 0;
float current_room_humid = 0;
#endif
+bool pwm_report_enable = true;
// Inputs
#define VINT_COUNT 16
@@ -54,9 +60,9 @@ unsigned long virtual_interupt_timer[VINT_COUNT];
#define PWM_COUNT 16
const uint8_t pwm_pins[PWM_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
bool pwm_states[PWM_COUNT];
-uint8_t pwm_states_eeprom[PWM_COUNT];
+uint8_t pwm_states_fram[PWM_COUNT];
uint16_t pwm_values[PWM_COUNT];
-uint8_t pwm_values_eeprom[PWM_COUNT * 2];
+uint8_t pwm_values_fram[PWM_COUNT * 2];
// output = m*input+c
const float pwm_linear_scaling_m[PWM_COUNT] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
const float pwm_linear_scaling_c[PWM_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -64,6 +70,7 @@ const float pwm_linear_scaling_c[PWM_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
const int PWM_CYCLE_VALUES[PWM_CYCLE_VALUES_COUNT] = {50, 125, 255};
char PWM_SET_STATE_TOPIC[70];
char PWM_SET_VALUE_TOPIC[70];
+char PWM_REPORT_ENABLE_TOPIC[70];
#ifdef ENABLE_INTERNAL_LCD
// LCD
@@ -78,7 +85,6 @@ Mode 0: Off, 1: Cool, 2: Fan
Fan Speed 0: Auto, 1: High, 2: Mid, 3: Low
*/
#ifdef ENABLE_CLIMATE_MODULE
-#define DHT22_PIN 32
uint8_t ac_mode = 0;
uint8_t ac_fan_speed = 0;
uint8_t ac_temperature = 25;
@@ -92,23 +98,50 @@ char AC_ROOM_TEMPERATURE_TOPIC[75];
char AC_HUMIDITY_TOPIC[75];
#endif
-// EEPROM ADDRESS
-#define EEPROM_ADDRESS_AC_MODE 0 // 01bytes
-#define EEPROM_ADDRESS_AC_TEMPERATURE 1 // 01bytes
-#define EEPROM_ADDRESS_AC_FAN_SPEED 2 // 01bytes
-#define EEPROM_ADDRESS_PWM_STATE 3 // 16bytes, thru 18
-#define EEPROM_ADDRESS_PWM_VALUE 19 // 32bytes, thru 50
-#define EEPROM_ADDRESS_HOSTNAME 65 // 15bytes, thru 79
-#define EEPROM_ADDRESS_TOPIC 80 // 20bytes, thru 99
-#define EEPROM_ADDRESS_IP 100 // 04bytes, thru 103
-#define EEPROM_ADDRESS_SUBNET 104 // 04bytes, thru 107
-#define EEPROM_ADDRESS_GATEWAY 108 // 04bytes, thru 111
-#define EEPROM_ADDRESS_DNS 112 // 04bytes, thru 115
-#define EEPROM_ADDRESS_MQTT_SERVER 116 // 04bytes, thru 119
-#define EEPROM_ADDRESS_MQTT_PORT 120 // 02bytes, thru 121
-#define EEPROM_ADDRESS_MQTT_USERNAME 122 // 32bytes, thru 153
-#define EEPROM_ADDRESS_MQTT_PASSWORD 154 // 32bytes, thru 185
-#define EEPROM_ADDRESS_MQTT_USEAUTH 186 // 1bytes
+#ifdef ENABLE_IR_MODULE
+uint16_t ir_buffer[IR_RAW_BUFFER_LENGTH];
+uint16_t ir_buffer_length = 0;
+#endif
+
+#ifdef ENABLE_ANALOG_MODULE
+#define DAC_COUNT 4
+#define ADC_COUNT 8
+bool dac_states[DAC_COUNT];
+uint16_t dac_values[DAC_COUNT];
+uint16_t adc_values[ADC_COUNT];
+bool adc_report_enable[ADC_COUNT];
+
+char ADC_COMMAND_TOPIC[75];
+char ADC_STATE_TOPIC[75];
+char ADC_REPORT_TOPIC[75];
+char DAC_SET_STATE_TOPIC[75];
+char DAC_SET_VALUE_TOPIC[75];
+char DAC_STATE_TOPIC[75];
+char DAC_VALUE_TOPIC[75];
+#endif
+
+// FRAM ADDRESS
+#define FRAM_ADDRESS_AC_MODE 0 // 01bytes
+#define FRAM_ADDRESS_AC_TEMPERATURE 1 // 01bytes
+#define FRAM_ADDRESS_AC_FAN_SPEED 2 // 01bytes
+#define FRAM_ADDRESS_PWM_STATE 3 // 16bytes, thru 18
+#define FRAM_ADDRESS_PWM_VALUE 19 // 32bytes, thru 50
+#define FRAM_ADDRESS_HOSTNAME 65 // 15bytes, thru 79
+#define FRAM_ADDRESS_TOPIC 80 // 20bytes, thru 99
+#define FRAM_ADDRESS_IP 100 // 04bytes, thru 103
+#define FRAM_ADDRESS_SUBNET 104 // 04bytes, thru 107
+#define FRAM_ADDRESS_GATEWAY 108 // 04bytes, thru 111
+#define FRAM_ADDRESS_DNS 112 // 04bytes, thru 115
+#define FRAM_ADDRESS_MQTT_SERVER 116 // 04bytes, thru 119
+#define FRAM_ADDRESS_MQTT_PORT 120 // 02bytes, thru 121
+#define FRAM_ADDRESS_MQTT_USERNAME 122 // 32bytes, thru 153
+#define FRAM_ADDRESS_MQTT_PASSWORD 154 // 32bytes, thru 185
+#define FRAM_ADDRESS_MQTT_USEAUTH 186 // 1bytes
+#define FRAM_ADDRESS_ADC_REPORT_STATE 187 // 8bytes, thru 194
+#define FRAM_ADDRESS_DAC_STATE 195 // 4bytes, thru 198
+#define FRAM_ADDRESS_DAC_VALUE 199 // 8bytes, thru 206
+#define FRAM_ADDRESS_WEBUI_USERNAME 207 // 32bytes, thru 238
+#define FRAM_ADDRESS_WEBUI_PASSWORD 239 // 32bytes, thru 270
char PWM_STATE_TOPIC[75];
char PWM_VALUE_TOPIC[75];
@@ -123,9 +156,10 @@ DHTNEW env_sensor(DHT22_PIN);
Thread mqtt_reconnector = Thread();
Thread environment_reporter = Thread();
-Thread eeprom_pwm_updater = Thread();
+Thread fram_pwm_updater = Thread();
Thread user_timer_tick = Thread();
-StaticThreadController<4> thread_controller(&mqtt_reconnector, &environment_reporter, &eeprom_pwm_updater, &user_timer_tick);
+Thread analog_handler = Thread();
+StaticThreadController<5> thread_controller(&mqtt_reconnector, &environment_reporter, &fram_pwm_updater, &user_timer_tick, &analog_handler);
#ifdef ENABLE_INTERNAL_LCD
Thread top_bar_updater = Thread();
@@ -144,14 +178,17 @@ void setup()
#endif
Serial.println("ESPMega R3 Initializing");
ESPMega_begin();
- #ifdef OVERCLOCK_FM2
+#ifdef OVERCLOCK_FM2
Wire.setClock(1000000);
- #endif
- #ifdef OVERCLOCK_FM
+#endif
+#ifdef OVERCLOCK_FM
Wire.setClock(400000);
- #endif
+#endif
io_begin();
- eeprom_retrieve_init();
+#ifdef VIRTUAL_INTERRUPT_PRELOAD
+ virtual_interrupt_preload();
+#endif
+ fram_retrieve_init();
user_pre_init();
#ifdef ENABLE_INTERNAL_LCD
lcd_send_stop_bit();
@@ -209,40 +246,54 @@ void loop()
}
/**
- * @brief Retrieves data from EEPROM and initializes various variables and topics.
+ * @brief Retrieves data from FRAM and initializes various variables and topics.
*
*/
-void eeprom_retrieve_init()
+void fram_retrieve_init()
{
-// EEPROM Data Retrival
-#ifdef ENABLE_CLIMATE_MODULE
- ac_mode = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_MODE);
- ac_temperature = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_TEMPERATURE);
- ac_fan_speed = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_FAN_SPEED);
+#ifdef ENABLE_WEBUI
+ ESPMega_FRAM.read(FRAM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32);
+ ESPMega_FRAM.read(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32);
+ if (strlen(WEBUI_USERNAME) == 0)
+ {
+ strcpy(WEBUI_USERNAME, "admin");
+ ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32);
+ }
+ if (strlen(WEBUI_PASSWORD) == 0)
+ {
+ strcpy(WEBUI_PASSWORD, "admin");
+ ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32);
+ }
#endif
-// EEPROM Data Retrival Validation
+// FRAM Data Retrival
+#ifdef ENABLE_CLIMATE_MODULE
+ ac_mode = ESPMega_FRAM.read8(FRAM_ADDRESS_AC_MODE);
+ ac_temperature = ESPMega_FRAM.read8(FRAM_ADDRESS_AC_TEMPERATURE);
+ ac_fan_speed = ESPMega_FRAM.read8(FRAM_ADDRESS_AC_FAN_SPEED);
+#endif
+// FRAM Data Retrival Validation
#ifdef ENABLE_CLIMATE_MODULE
if (ac_mode > 2)
{
ac_mode = 0;
- ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_MODE, ac_mode);
+ ESPMega_FRAM.write8(FRAM_ADDRESS_AC_MODE, ac_mode);
}
if (ac_temperature > AC_MAX_TEMPERATURE || ac_temperature < AC_MIN_TEMPERATURE)
{
ac_temperature = AC_MAX_TEMPERATURE;
- ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_temperature);
+ ESPMega_FRAM.write8(FRAM_ADDRESS_AC_TEMPERATURE, ac_temperature);
}
if (ac_fan_speed > 3)
{
ac_fan_speed = 0;
- ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_fan_speed);
+ ESPMega_FRAM.write8(FRAM_ADDRESS_AC_TEMPERATURE, ac_fan_speed);
}
ac_set_state(ac_mode, ac_temperature, ac_fan_speed);
#endif
- ESPMega_FRAM.read(EEPROM_ADDRESS_PWM_STATE, pwm_states_eeprom, 16);
- memcpy(pwm_states, pwm_states_eeprom, 16);
- ESPMega_FRAM.read(EEPROM_ADDRESS_PWM_VALUE, pwm_values_eeprom, 32);
- memcpy(pwm_values, pwm_values_eeprom, 32);
+ ESPMega_FRAM.read(FRAM_ADDRESS_PWM_STATE, pwm_states_fram, 16);
+ memcpy(pwm_states, pwm_states_fram, 16);
+ ESPMega_FRAM.read(FRAM_ADDRESS_PWM_VALUE, pwm_values_fram, 32);
+ memcpy(pwm_values, pwm_values_fram, 32);
for (int i = 0; i < 15; i++)
{
if (pwm_states[i] <= 1)
@@ -254,18 +305,18 @@ void eeprom_retrieve_init()
else
pwm_set_value(i, 0);
}
- IP = eeprom_ip_retrieve(EEPROM_ADDRESS_IP);
- SUBNET = eeprom_ip_retrieve(EEPROM_ADDRESS_SUBNET);
- GATEWAY = eeprom_ip_retrieve(EEPROM_ADDRESS_GATEWAY);
- DNS = eeprom_ip_retrieve(EEPROM_ADDRESS_DNS);
- MQTT_SERVER = eeprom_ip_retrieve(EEPROM_ADDRESS_MQTT_SERVER);
- eeprom_hostname_retrieve();
- eeprom_mqtt_port_retrieve();
- eeprom_mqtt_useauth_retrieve();
- eeprom_mqtt_username_retrieve();
- eeprom_mqtt_password_retrieve();
+ IP = fram_ip_retrieve(FRAM_ADDRESS_IP);
+ SUBNET = fram_ip_retrieve(FRAM_ADDRESS_SUBNET);
+ GATEWAY = fram_ip_retrieve(FRAM_ADDRESS_GATEWAY);
+ DNS = fram_ip_retrieve(FRAM_ADDRESS_DNS);
+ MQTT_SERVER = fram_ip_retrieve(FRAM_ADDRESS_MQTT_SERVER);
+ fram_hostname_retrieve();
+ fram_mqtt_port_retrieve();
+ fram_mqtt_useauth_retrieve();
+ fram_mqtt_username_retrieve();
+ fram_mqtt_password_retrieve();
mqtt.setServer(MQTT_SERVER, MQTT_PORT);
- eeprom_basetopic_retrieve();
+ fram_basetopic_retrieve();
base_topic_length = strlen(MQTT_BASE_TOPIC) + 1;
memcpy(STATE_REQUEST_TOPIC, MQTT_BASE_TOPIC, 20);
strcat(STATE_REQUEST_TOPIC, "/requeststate");
@@ -273,6 +324,8 @@ void eeprom_retrieve_init()
strcat(PWM_SET_STATE_TOPIC, "/pwm/00/set/state");
memcpy(PWM_SET_VALUE_TOPIC, MQTT_BASE_TOPIC, 20);
strcat(PWM_SET_VALUE_TOPIC, "/pwm/00/set/value");
+ memcpy(PWM_REPORT_ENABLE_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(PWM_REPORT_ENABLE_TOPIC, "/pwm/report_enable");
#ifdef ENABLE_CLIMATE_MODULE
memcpy(AC_SET_MODE_TOPIC, MQTT_BASE_TOPIC, 20);
strcat(AC_SET_MODE_TOPIC, "/ac/set/mode");
@@ -297,6 +350,32 @@ void eeprom_retrieve_init()
strcat(PWM_VALUE_TOPIC, "/pwm/00/value");
memcpy(INPUTS_TOPIC, MQTT_BASE_TOPIC, 20);
strcat(INPUTS_TOPIC, "/input/00");
+ memcpy(AVAILABILITY_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(AVAILABILITY_TOPIC, "/availability");
+#ifdef ENABLE_ANALOG_MODULE
+ memcpy(ADC_COMMAND_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(ADC_COMMAND_TOPIC, "/adc/00/set/state");
+ memcpy(ADC_STATE_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(ADC_STATE_TOPIC, "/adc/00/state");
+ memcpy(ADC_REPORT_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(ADC_REPORT_TOPIC, "/adc/00/report");
+ memcpy(DAC_SET_STATE_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(DAC_SET_STATE_TOPIC, "/dac/00/set/state");
+ memcpy(DAC_SET_VALUE_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(DAC_SET_VALUE_TOPIC, "/dac/00/set/value");
+ memcpy(DAC_STATE_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(DAC_STATE_TOPIC, "/dac/00/state");
+ memcpy(DAC_VALUE_TOPIC, MQTT_BASE_TOPIC, 20);
+ strcat(DAC_VALUE_TOPIC, "/dac/00/value");
+ ESPMega_FRAM.read(FRAM_ADDRESS_ADC_REPORT_STATE, (uint8_t *)adc_report_enable, 8);
+ ESPMega_FRAM.read(FRAM_ADDRESS_DAC_STATE, (uint8_t *)dac_states, 4);
+ ESPMega_FRAM.read(FRAM_ADDRESS_DAC_VALUE, (uint8_t *)dac_values, 8);
+ for (int i = 0; i < DAC_COUNT; i++)
+ {
+ dac_set_state(i, dac_states[i]);
+ dac_set_value(i, dac_values[i]);
+ }
+#endif
}
#ifdef ENABLE_WEBUI
@@ -314,12 +393,19 @@ void ota_begin()
{
otaserver.on("/", HTTP_GET, []()
{
+ if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD))
+ return otaserver.requestAuthentication();
otaserver.sendHeader("Connection", "close");
String otabuffer = ota_part1;
otabuffer+=ota_part2_1+"Hostname"+ota_part2_2+String(HOSTNAME)+ota_part2_3;
otabuffer+=ota_part2_1+"IP Address"+ota_part2_2+IP.toString()+ota_part2_3;
otabuffer+=ota_part2_1+"MAC Address"+ota_part2_2+ETH.macAddress()+ota_part2_3;
otabuffer+=ota_part2_1+"Device"+ota_part2_2+ESPMEGA_REV+ota_part2_3;
+#ifdef FW_VERSION
+ otabuffer+=ota_part2_1+"Firmware"+ota_part2_2+FW_VERSION+ota_part2_3;
+#else
+ otabuffer+=ota_part2_1+"Firmware"+ota_part2_2+"Out of Tree"+ota_part2_3;
+#endif
otabuffer+=ota_part2_1+"BMS Server"+ota_part2_2+MQTT_SERVER.toString()+ota_part2_3;
otabuffer+=ota_part2_1+"BMS Endpoint"+ota_part2_2+String(MQTT_BASE_TOPIC)+ota_part2_3;
otabuffer+=ota_part2_1+"Centrally Managed"+ota_part2_2;
@@ -331,6 +417,8 @@ void ota_begin()
otaserver.send(200, "text/html", otabuffer); });
otaserver.on("/config", HTTP_GET, []()
{
+ if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD))
+ return otaserver.requestAuthentication();
otaserver.sendHeader("Connection", "close");
String configbuffer = config_part1;
configbuffer+=config_txt_part1+"IP Address"+config_txt_part2+"text"+config_txt_part3+"dev_ip"+config_txt_part4+"dev_ip"+config_txt_part5+IP.toString()+config_txt_part6;
@@ -344,11 +432,15 @@ void ota_begin()
configbuffer+=config_txt_part1+"BMS Server - Username"+config_txt_part2+"text"+config_txt_part3+"bms_username"+config_txt_part4+"bms_username"+config_txt_part5+String(MQTT_USERNAME)+config_txt_part6;
configbuffer+=config_txt_part1+"BMS Server - Password"+config_txt_part2+"password"+config_txt_part3+"bms_password"+config_txt_part4+"bms_password"+config_txt_part5+String(MQTT_PASSWORD)+config_txt_part6;
configbuffer+=config_txt_part1+"BMS Server - Endpoint"+config_txt_part2+"text"+config_txt_part3+"bms_endpoint"+config_txt_part4+"bms_endpoint"+config_txt_part5+String(MQTT_BASE_TOPIC)+config_txt_part6;
+ configbuffer+=config_txt_part1+"WebUI Username"+config_txt_part2+"text"+config_txt_part3+"webui_username"+config_txt_part4+"webui_username"+config_txt_part5+String(WEBUI_USERNAME)+config_txt_part6;
+ configbuffer+=config_txt_part1+"WebUI Password"+config_txt_part2+"password"+config_txt_part3+"webui_password"+config_txt_part4+"webui_password"+config_txt_part5+String(WEBUI_PASSWORD)+config_txt_part6;
configbuffer+=config_part2;
otaserver.send(200, "text/html", configbuffer); });
otaserver.on("/save_config", HTTP_GET, []()
{
+ if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD))
+ return otaserver.requestAuthentication();
otaserver.sendHeader("Connection", "close");
String configbuffer = "Configuration Saved. Rebooting . . .";
otaserver.send(200, "text/html", configbuffer);
@@ -381,6 +473,10 @@ void ota_begin()
} else if(!arg.compareTo("bms_useauth")) {
if(!value.compareTo("yes"))
use_auth = true;
+ } else if(!arg.compareTo("webui_username")) {
+ ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_USERNAME, (uint8_t *)value.c_str(), value.length()+1);
+ } else if(!arg.compareTo("webui_password")) {
+ ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)value.c_str(), value.length()+1);
}
}
set_mqtt_useauth(use_auth);
@@ -391,6 +487,8 @@ void ota_begin()
otaserver.on(
"/update", HTTP_POST, []()
{
+ if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD))
+ return otaserver.requestAuthentication();
otaserver.sendHeader("Connection", "close");
otaserver.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart(); },
@@ -520,13 +618,14 @@ void mqtt_connect()
Serial.print("MQTT not connected, connecting . . .\n");
lcd_send_stop_bit();
if (MQTT_USE_AUTH)
- mqtt.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD);
+ mqtt.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD, AVAILABILITY_TOPIC, 0, true, "offline");
else
- mqtt.connect(HOSTNAME);
+ mqtt.connect(HOSTNAME, AVAILABILITY_TOPIC, 0, true, "offline");
if (mqtt.connected())
{
mqtt_subscribe();
Serial.print("MQTT connected\n");
+ mqtt.publish(AVAILABILITY_TOPIC, "online", true);
lcd_send_stop_bit();
publish_pwm_states();
publish_input_states();
@@ -534,6 +633,12 @@ void mqtt_connect()
publish_ac_state();
#endif
mqtt_connected_user_callback();
+#ifdef ENABLE_ANALOG_MODULE
+ publish_dac_states();
+ publish_dac_values();
+ publish_adc_values();
+ publish_adc_states();
+#endif
standalone = false;
ESPMega_updateTimeFromNTP();
}
@@ -566,12 +671,30 @@ void mqtt_subscribe()
mqtt.subscribe(PWM_SET_STATE_TOPIC);
mqtt.subscribe(PWM_SET_VALUE_TOPIC);
}
+ mqtt.subscribe(PWM_REPORT_ENABLE_TOPIC);
#ifdef ENABLE_CLIMATE_MODULE
mqtt.subscribe(AC_SET_FAN_TOPIC);
mqtt.subscribe(AC_SET_TEMPERATURE_TOPIC);
mqtt.subscribe(AC_SET_MODE_TOPIC);
#endif
mqtt.subscribe(STATE_REQUEST_TOPIC);
+#ifdef ENABLE_ANALOG_MODULE
+ for (int i = 0; i < ADC_COUNT; i++)
+ {
+ ADC_COMMAND_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0';
+ ADC_COMMAND_TOPIC[base_topic_length + 5] = (i % 10) + '0';
+ mqtt.subscribe(ADC_COMMAND_TOPIC);
+ }
+ for (int i = 0; i < DAC_COUNT; i++)
+ {
+ DAC_SET_STATE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0';
+ DAC_SET_STATE_TOPIC[base_topic_length + 5] = (i % 10) + '0';
+ DAC_SET_VALUE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0';
+ DAC_SET_VALUE_TOPIC[base_topic_length + 5] = (i % 10) + '0';
+ mqtt.subscribe(DAC_SET_STATE_TOPIC);
+ mqtt.subscribe(DAC_SET_VALUE_TOPIC);
+ }
+#endif
}
/**
@@ -581,7 +704,7 @@ void mqtt_subscribe()
* @param payload The payload of the received message.
* @param length The length of the payload.
*/
-void mqtt_callback(char *topic, byte *payload, unsigned int length)
+IRAM_ATTR void mqtt_callback(char *topic, byte *payload, unsigned int length)
{
uint8_t topic_length = strlen(topic);
char topic_trim[50];
@@ -597,6 +720,37 @@ void mqtt_callback(char *topic, byte *payload, unsigned int length)
{
pwm_value_callback(topic_trim, topic_length, payload_nt, length);
}
+ else if (!strcmp(topic_trim, "/pwm/report_enable"))
+ {
+ pwm_set_publish_callback(topic_trim, topic_length, payload_nt, length);
+ }
+#ifdef ENABLE_ANALOG_MODULE
+ else if ((!strncmp(topic_trim, "/adc/", 5)) && !strncmp(topic_trim + 7, "/set/state", 10))
+ {
+ adc_set_state_callback(topic_trim, topic_length, payload_nt, length);
+ }
+ else if ((!strncmp(topic_trim, "/dac/", 5)) && !strncmp(topic_trim + 7, "/set/state", 10))
+ {
+ dac_set_state_callback(topic_trim, topic_length, payload_nt, length);
+ }
+ else if ((!strncmp(topic_trim, "/dac/", 5)) && !strncmp(topic_trim + 7, "/set/value", 10))
+ {
+ dac_set_value_callback(topic_trim, topic_length, payload_nt, length);
+ }
+#endif
+#ifdef ENABLE_IR_MODULE
+ else if (!strcmp(topic_trim, "/ir/send"))
+ {
+ const char *delimiter = ",";
+ char *token = strtok(const_cast(payload_nt), delimiter);
+ while (token != nullptr && ir_buffer_length < IR_RAW_BUFFER_LENGTH)
+ {
+ ir_buffer[ir_buffer_length++] = atoi(token);
+ token = strtok(nullptr, delimiter);
+ }
+ IrSender.sendRaw(ir_buffer, ir_buffer_length, NEC_KHZ);
+ }
+#endif
else if (!strcmp(topic, STATE_REQUEST_TOPIC))
{
state_request_callback();
@@ -611,7 +765,7 @@ void mqtt_callback(char *topic, byte *payload, unsigned int length)
}
/**
- * @brief Initializes the threads for various tasks such as MQTT connection, environment reporting, EEPROM PWM update, and user timer tick.
+ * @brief Initializes the threads for various tasks such as MQTT connection, environment reporting, FRAM PWM update, and user timer tick.
*
*/
void thread_initialization()
@@ -624,10 +778,14 @@ void thread_initialization()
environment_reporter.onRun(publish_env_state);
environment_reporter.setInterval(5000);
#endif
- eeprom_pwm_updater.onRun(eeprom_pwm_update);
- eeprom_pwm_updater.setInterval(1000);
+ fram_pwm_updater.onRun(fram_pwm_update);
+ fram_pwm_updater.setInterval(1000);
user_timer_tick.onRun(timer_tick_callback);
user_timer_tick.setInterval(15000);
+#ifdef ENABLE_ANALOG_MODULE
+ analog_handler.onRun(adc_loop);
+ analog_handler.setInterval(ANALOG_REPORTING_INTERVAL);
+#endif
}
/**
@@ -638,7 +796,7 @@ void thread_initialization()
* @param payload The message payload.
* @param payload_length The length of the message payload.
*/
-void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
+IRAM_ATTR void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
{
int a = topic[5] - '0';
int b = topic[6] - '0';
@@ -664,7 +822,7 @@ void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsign
* @param payload The message payload.
* @param payload_length The length of the message payload.
*/
-void pwm_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
+IRAM_ATTR void pwm_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
{
int a = topic[5] - '0';
int b = topic[6] - '0';
@@ -723,6 +881,7 @@ void publish_pwm_states()
for (int i = 0; i < PWM_COUNT; i++)
{
publish_pwm_state(i);
+ publish_pwm_value(i);
}
}
@@ -733,12 +892,11 @@ void publish_pwm_states()
*/
void publish_pwm_state(int id)
{
+ if (!pwm_report_enable)
+ return;
int state = pwm_states[id];
- int value = pwm_values[id];
PWM_STATE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
PWM_STATE_TOPIC[base_topic_length + 5] = (id % 10) + '0';
- PWM_VALUE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
- PWM_VALUE_TOPIC[base_topic_length + 5] = (id % 10) + '0';
if (state == 1)
{
mqtt.publish(PWM_STATE_TOPIC, "on");
@@ -747,6 +905,15 @@ void publish_pwm_state(int id)
{
mqtt.publish(PWM_STATE_TOPIC, "off");
}
+}
+
+void publish_pwm_value(int id)
+{
+ if (!pwm_report_enable)
+ return;
+ int value = pwm_values[id];
+ PWM_VALUE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
+ PWM_VALUE_TOPIC[base_topic_length + 5] = (id % 10) + '0';
char temp[6];
itoa(value, temp, DEC);
mqtt.publish(PWM_VALUE_TOPIC, temp);
@@ -758,7 +925,7 @@ void publish_pwm_state(int id)
* @param id The ID of the PWM pin.
* @param state The new state of the PWM pin.
*/
-void pwm_set_state(int id, int state)
+IRAM_ATTR void pwm_set_state(int id, int state)
{
if (state != pwm_states[id])
{
@@ -782,7 +949,7 @@ void pwm_set_state(int id, int state)
* @param id The id of the PWM pin.
* @param value The value to set the PWM pin to.
*/
-void pwm_set_value(int id, int value)
+IRAM_ATTR void pwm_set_value(int id, int value)
{
pwm_values[id] = value;
int pwm_state = pwm_states[id];
@@ -793,7 +960,7 @@ void pwm_set_value(int id, int value)
else if (lcd_current_page == 5 && id == lcd_pwmAdj_id)
panel.writeNum("pwm_value.val", pwm_values[lcd_pwmAdj_id]);
#endif
- publish_pwm_state(id);
+ publish_pwm_value(id);
pwm_changed_user_callback(id);
}
@@ -909,6 +1076,11 @@ void publish_input_state(int id, int state)
mqtt.publish(INPUTS_TOPIC, state ? "1" : "0");
}
+void pwm_set_publish_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
+{
+ pwm_report_enable = !strcmp(payload, "on");
+}
+
/**
* @brief Callback function to request the current state of the device.
*
@@ -919,11 +1091,18 @@ void state_request_callback()
{
publish_input_states();
publish_pwm_states();
+ pwm_report_enable = true;
#ifdef ENABLE_CLIMATE_MODULE
publish_ac_state();
publish_env_state();
#endif
user_state_request_callback();
+#ifdef ENABLE_ANALOG_MODULE
+ publish_adc_states();
+ publish_adc_values();
+ publish_dac_states();
+ publish_dac_values();
+#endif
}
#ifdef ENABLE_IR_MODULE
@@ -1089,6 +1268,8 @@ void ac_set_state(int mode, int temperature, int fan_speed)
*/
void publish_env_state()
{
+ if(!pwm_report_enable)
+ return;
int errorCode = env_sensor.read();
yield();
switch (errorCode)
@@ -1412,34 +1593,34 @@ void trigger15()
#endif // End Internal LCD Code Block
/**
- * @brief Updates the PWM states and values in EEPROM if they have changed.
+ * @brief Updates the PWM states and values in FRAM if they have changed.
*
- * If the current PWM states or values are different from the ones stored in EEPROM,
- * this function updates the EEPROM with the current values.
+ * If the current PWM states or values are different from the ones stored in FRAM,
+ * this function updates the FRAM with the current values.
*/
-void eeprom_pwm_update()
+void fram_pwm_update()
{
- if (memcmp(pwm_states, pwm_states_eeprom, 16))
+ if (memcmp(pwm_states, pwm_states_fram, 16))
{
- memcpy(pwm_states_eeprom, pwm_states, 16);
- ESPMega_FRAM.write(3, pwm_states_eeprom, 16);
+ memcpy(pwm_states_fram, pwm_states, 16);
+ ESPMega_FRAM.write(3, pwm_states_fram, 16);
}
- if (memcmp(pwm_values, pwm_values_eeprom, 32))
+ if (memcmp(pwm_values, pwm_values_fram, 32))
{
- memcpy(pwm_values_eeprom, pwm_values, 32);
- ESPMega_FRAM.write(19, pwm_values_eeprom, 32);
+ memcpy(pwm_values_fram, pwm_values, 32);
+ ESPMega_FRAM.write(19, pwm_values_fram, 32);
}
}
/**
- * @brief Sets the IP address and updates it in EEPROM.
+ * @brief Sets the IP address and updates it in FRAM.
*
* @param address The IP address to set.
*/
void set_ip(String address)
{
IP.fromString(address);
- eeprom_ip_update(EEPROM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]);
+ fram_ip_update(FRAM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]);
}
/**
@@ -1450,7 +1631,7 @@ void set_ip(String address)
void set_netmask(String address)
{
SUBNET.fromString(address);
- eeprom_ip_update(EEPROM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]);
+ fram_ip_update(FRAM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]);
}
/**
@@ -1460,33 +1641,33 @@ void set_netmask(String address)
void set_dns(String address)
{
DNS.fromString(address);
- eeprom_ip_update(EEPROM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]);
+ fram_ip_update(FRAM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]);
}
/**
- * @brief Sets the gateway IP address and updates the EEPROM.
+ * @brief Sets the gateway IP address and updates the FRAM.
*
* @param address The gateway IP address as a String.
*/
void set_gw(String address)
{
GATEWAY.fromString(address);
- eeprom_ip_update(EEPROM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]);
+ fram_ip_update(FRAM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]);
}
/**
- * @brief Sets the MQTT server address and updates the EEPROM.
+ * @brief Sets the MQTT server address and updates the FRAM.
*
* @param address The MQTT server address as a String.
*/
void set_mqtt_server(String address)
{
MQTT_SERVER.fromString(address);
- eeprom_ip_update(EEPROM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]);
+ fram_ip_update(FRAM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]);
}
/**
- * @brief Updates the IP address in EEPROM at the specified ROM address.
+ * @brief Updates the IP address in FRAM at the specified ROM address.
*
* @param rom_address The ROM address where the IP address is stored.
* @param byte1 The first byte of the IP address.
@@ -1494,19 +1675,19 @@ void set_mqtt_server(String address)
* @param byte3 The third byte of the IP address.
* @param byte4 The fourth byte of the IP address.
*/
-void eeprom_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
+void fram_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
{
uint8_t addressblock[4] = {byte1, byte2, byte3, byte4};
ESPMega_FRAM.write(rom_address, addressblock, 4);
}
/**
- * @brief Retrieves an IP address from EEPROM memory.
+ * @brief Retrieves an IP address from FRAM memory.
*
- * @param rom_address The address in EEPROM memory where the IP address is stored.
+ * @param rom_address The address in FRAM memory where the IP address is stored.
* @return The retrieved IP address.
*/
-IPAddress eeprom_ip_retrieve(uint16_t rom_address)
+IPAddress fram_ip_retrieve(uint16_t rom_address)
{
uint8_t addressblock[4];
ESPMega_FRAM.read(rom_address, addressblock, 4);
@@ -1521,40 +1702,40 @@ IPAddress eeprom_ip_retrieve(uint16_t rom_address)
void set_hostname(String hostname)
{
hostname.toCharArray(HOSTNAME, 15);
- ESPMega_FRAM.write(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15);
+ ESPMega_FRAM.write(FRAM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15);
}
/**
- * @brief Retrieves the hostname from EEPROM and stores it in the HOSTNAME variable.
+ * @brief Retrieves the hostname from FRAM and stores it in the HOSTNAME variable.
*
*/
-void eeprom_hostname_retrieve()
+void fram_hostname_retrieve()
{
- ESPMega_FRAM.read(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15);
+ ESPMega_FRAM.read(FRAM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15);
}
/**
- * @brief Sets the base topic for MQTT communication and writes it to EEPROM.
+ * @brief Sets the base topic for MQTT communication and writes it to FRAM.
*
* @param topic The base topic to set.
*/
void set_basetopic(String topic)
{
topic.toCharArray(MQTT_BASE_TOPIC, 20);
- ESPMega_FRAM.write(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20);
+ ESPMega_FRAM.write(FRAM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20);
}
/**
- * @brief Retrieves the MQTT base topic from EEPROM and stores it in MQTT_BASE_TOPIC array.
+ * @brief Retrieves the MQTT base topic from FRAM and stores it in MQTT_BASE_TOPIC array.
*
*/
-void eeprom_basetopic_retrieve()
+void fram_basetopic_retrieve()
{
- ESPMega_FRAM.read(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20);
+ ESPMega_FRAM.read(FRAM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20);
}
/**
- * @brief Sets the MQTT port in the EEPROM.
+ * @brief Sets the MQTT port in the FRAM.
*
* @param port The MQTT port to be set.
*/
@@ -1562,16 +1743,16 @@ void mqtt_port_set(uint16_t port)
{
uint8_t port_arr[2];
memcpy(port_arr, &port, 2);
- ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2);
+ ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_PORT, port_arr, 2);
}
/**
- * @brief Retrieves the MQTT port from EEPROM and stores it in the MQTT_PORT variable.
+ * @brief Retrieves the MQTT port from FRAM and stores it in the MQTT_PORT variable.
*
*/
-void eeprom_mqtt_port_retrieve()
+void fram_mqtt_port_retrieve()
{
uint8_t port_arr[2];
- ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2);
+ ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_PORT, port_arr, 2);
memcpy(&MQTT_PORT, port_arr, 2);
}
@@ -1639,57 +1820,71 @@ uint8_t ac_get_fan_speed()
#endif
/**
- * @brief Retrieves the MQTT username from EEPROM and stores it in the MQTT_USERNAME global variable.
+ * @brief Retrieves the MQTT username from FRAM and stores it in the MQTT_USERNAME global variable.
*
*/
-void eeprom_mqtt_username_retrieve()
+void fram_mqtt_username_retrieve()
{
- ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32);
+ ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32);
}
/**
- * @brief Retrieves the MQTT password from EEPROM and stores it in the MQTT_PASSWORD global variable.
+ * @brief Retrieves the MQTT password from FRAM and stores it in the MQTT_PASSWORD global variable.
*
*/
-void eeprom_mqtt_password_retrieve()
+void fram_mqtt_password_retrieve()
{
- ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32);
+ ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32);
}
/**
- * @brief Sets the MQTT username and writes it to the EEPROM.
+ * @brief Sets the MQTT username and writes it to the FRAM.
*
* @param username The MQTT username to set.
*/
void set_mqtt_username(String username)
{
username.toCharArray(MQTT_USERNAME, 32);
- ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20);
+ ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20);
}
/**
- * @brief Sets the MQTT password and writes it to the EEPROM.
+ * @brief Sets the MQTT password and writes it to the FRAM.
*
* @param password The MQTT password to set.
*/
void set_mqtt_password(String password)
{
password.toCharArray(MQTT_PASSWORD, 32);
- ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20);
+ ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20);
}
-void eeprom_mqtt_useauth_retrieve()
+void fram_mqtt_useauth_retrieve()
{
- MQTT_USE_AUTH = ESPMega_FRAM.read8(EEPROM_ADDRESS_MQTT_USEAUTH);
+ MQTT_USE_AUTH = ESPMega_FRAM.read8(FRAM_ADDRESS_MQTT_USEAUTH);
}
/**
- * @brief Sets the MQTT_USE_AUTH flag and writes it to the EEPROM.
+ * @brief Sets the MQTT_USE_AUTH flag and writes it to the FRAM.
*
* @param use_auth A boolean value indicating whether to use authentication for MQTT.
*/
void set_mqtt_useauth(bool use_auth)
{
MQTT_USE_AUTH = use_auth;
- ESPMega_FRAM.write8(EEPROM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH);
+ ESPMega_FRAM.write8(FRAM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH);
}
+#ifdef ENABLE_WEBUI
+void set_webui_username(String username)
+{
+ username.toCharArray(WEBUI_USERNAME, 32);
+ ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32);
+}
+
+void set_webui_password(String password)
+{
+ password.toCharArray(WEBUI_PASSWORD, 32);
+ ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32);
+}
+#endif
+
/**
* @brief Resets the device to factory default settings.
*
@@ -1725,6 +1920,11 @@ void factory_reset()
set_ip("192.168.0.10");
set_gw("192.168.0.1");
set_netmask("255.255.255.0");
+#ifdef ENABLE_WEBUI
+ set_webui_username("admin");
+ set_webui_password("admin");
+#endif
+
// Reboot
#ifdef ENABLE_INTERNAL_LCD
lcd_send_stop_bit();
@@ -1747,4 +1947,359 @@ void check_boot_reset()
{
factory_reset();
}
+}
+
+#ifdef ENABLE_ANALOG_MODULE
+/**
+ * Enables the ADC reporting for the specified ID.
+ *
+ * @param id The ID of the ADC to enable reporting for.
+ */
+void enable_adc(int id)
+{
+ adc_report_enable[id] = true;
+ ESPMega_FRAM.write8(FRAM_ADDRESS_ADC_REPORT_STATE + id, 1);
+ publish_adc_state(id);
+}
+/**
+ * @brief Disables the ADC reporting for the specified ID.
+ *
+ * This function sets the adc_report_enable flag to false for the specified ID and writes the state to the FRAM.
+ *
+ * @param id The ID of the ADC to disable reporting for.
+ */
+void disable_adc(int id)
+{
+ adc_report_enable[id] = false;
+ ESPMega_FRAM.write8(FRAM_ADDRESS_ADC_REPORT_STATE + id, 0);
+ publish_adc_state(id);
+}
+
+/**
+ * Publishes the state of an ADC (Analog-to-Digital Converter) to the MQTT broker.
+ *
+ * @param id The ID of the ADC.
+ */
+void publish_adc_state(int id)
+{
+ ADC_STATE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
+ ADC_STATE_TOPIC[base_topic_length + 5] = (id % 10) + '0';
+ mqtt.publish(ADC_STATE_TOPIC, adc_report_enable[id] ? "on" : "off");
+}
+
+/**
+ * @brief Publishes the ADC states.
+ *
+ * This function iterates over the ADC channels and publishes the state of each channel.
+ */
+void publish_adc_states()
+{
+ for (int i = 0; i < ADC_COUNT; i++)
+ {
+ publish_adc_state(i);
+ }
+}
+
+/**
+ * @brief Updates the ADC value for the specified ID if ADC reporting is enabled.
+ *
+ * @param id The ID of the ADC channel.
+ */
+void adc_update(int id)
+{
+ if (adc_report_enable[id])
+ {
+ adc_values[id] = ESPMega_analogRead(id);
+ }
+}
+
+/**
+ * @brief Updates the ADC value for the specified ID, do so even if reporting is disabled..
+ *
+ * @param id The ID of the ADC pin.
+ */
+void adc_update_force(int id)
+{
+ adc_values[id] = ESPMega_analogRead(id);
+}
+
+/**
+ * @brief Updates all ADC channels.
+ *
+ * This function updates all ADC channels by calling the `adc_update` function for each channel.
+ *
+ * @return void
+ */
+void adc_update_all()
+{
+ for (int i = 0; i < ADC_COUNT; i++)
+ {
+ adc_update(i);
+ }
+}
+
+/**
+ * @brief Performs ADC loop operations.
+ *
+ * This function updates all ADC values and publishes them.
+ */
+void adc_loop()
+{
+ adc_update_all();
+ publish_adc_values();
+}
+
+/**
+ * Publishes the ADC value to the MQTT broker.
+ *
+ * @param id The ID of the ADC channel.
+ */
+void publish_adc_value(int id)
+{
+ ADC_REPORT_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
+ ADC_REPORT_TOPIC[base_topic_length + 5] = (id % 10) + '0';
+ char temp[8];
+ itoa(adc_values[id], temp, DEC);
+ mqtt.publish(ADC_REPORT_TOPIC, temp);
+}
+
+/**
+ * Publishes the values of all enabled ADC channels.
+ * This function iterates through all ADC channels and publishes the values
+ * of the enabled channels using the publish_adc() function.
+ */
+void publish_adc_values()
+{
+ for (int i = 0; i < ADC_COUNT; i++)
+ {
+ if (adc_report_enable[i])
+ publish_adc_value(i);
+ }
+}
+
+/**
+ * Publishes the state of a DAC (Digital-to-Analog Converter) to the MQTT broker.
+ *
+ * @param id The ID of the DAC.
+ */
+void publish_dac_state(int id)
+{
+ DAC_STATE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
+ DAC_STATE_TOPIC[base_topic_length + 5] = (id % 10) + '0';
+ mqtt.publish(DAC_STATE_TOPIC, dac_states[id] ? "on" : "off");
+}
+
+/**
+ * Publishes the DAC value for a given ID.
+ *
+ * @param id The ID of the DAC value to publish.
+ */
+void publish_dac_value(int id)
+{
+ DAC_VALUE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0';
+ DAC_VALUE_TOPIC[base_topic_length + 5] = (id % 10) + '0';
+ char temp[6];
+ itoa(dac_values[id], temp, DEC);
+ mqtt.publish(DAC_VALUE_TOPIC, temp);
+}
+
+/**
+ * @brief Retrieves the ADC value for the specified ID.
+ *
+ * This function checks if the ADC report is enabled for the given ID. If not, it forces an update.
+ * It then returns the ADC value for the specified ID.
+ *
+ * @param id The ID of the ADC channel.
+ * @return The ADC value for the specified ID.
+ */
+uint16_t get_adc_value(int id)
+{
+ if (!adc_report_enable[id])
+ adc_update_force(id);
+ return adc_values[id];
+}
+
+/**
+ * @brief Sets the state of an ADC based on the received MQTT message.
+ *
+ * This function is called when an MQTT message is received to set the state of an ADC (Analog-to-Digital Converter).
+ * The function extracts the ADC ID from the topic and enables or disables the ADC based on the payload value.
+ *
+ * @param topic The topic of the MQTT message.
+ * @param topic_length The length of the topic.
+ * @param payload The payload of the MQTT message.
+ * @param payload_length The length of the payload.
+ */
+void adc_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
+{
+ int a = topic[5] - '0';
+ int b = topic[6] - '0';
+ int id = 10 * a + b;
+ if (!strcmp(payload, "on"))
+ {
+ enable_adc(id);
+ }
+ else if (!strcmp(payload, "off"))
+ {
+ disable_adc(id);
+ }
+}
+
+/**
+ * @brief Sets the value of a DAC channel.
+ *
+ * This function sets the value of a DAC channel specified by the `id` parameter.
+ * The `value` parameter represents the desired value for the DAC channel.
+ * The function updates the internal DAC value array, writes the value to the DAC,
+ * and also stores the value in the FRAM memory.
+ *
+ * @param id The ID of the DAC channel.
+ * @param value The desired value for the DAC channel.
+ */
+void dac_set_value(int id, int value)
+{
+ dac_values[id] = value;
+ ESPMega_dacWrite(id, dac_values[id] * dac_states[id]);
+ ESPMega_FRAM.write16(FRAM_ADDRESS_DAC_VALUE + id * 2, dac_values[id]);
+ publish_dac_value(id);
+}
+
+/**
+ * @brief Sets the state of a DAC channel.
+ *
+ * This function updates the state of a DAC channel and writes the new state to the DAC output.
+ * It also saves the state to the FRAM for persistence across power cycles.
+ *
+ * @param id The ID of the DAC channel.
+ * @param state The new state of the DAC channel.
+ */
+void dac_set_state(int id, bool state)
+{
+ dac_states[id] = state;
+ ESPMega_dacWrite(id, dac_values[id] * dac_states[id]);
+ ESPMega_FRAM.write8(FRAM_ADDRESS_DAC_STATE + id, dac_states[id]);
+ publish_dac_state(id);
+}
+
+/**
+ * @brief Publishes the states of all DACs.
+ *
+ * This function iterates through all DACs and publishes their states.
+ *
+ * @return void
+ */
+void publish_dac_states()
+{
+ for (int i = 0; i < DAC_COUNT; i++)
+ {
+ publish_dac_state(i);
+ }
+}
+
+/**
+ * @brief Publishes the DAC values.
+ *
+ * This function iterates through all the DAC channels and publishes their values.
+ *
+ * @return void
+ */
+void publish_dac_values()
+{
+ for (int i = 0; i < DAC_COUNT; i++)
+ {
+ publish_dac_value(i);
+ }
+}
+
+/**
+ * @brief Sets the value of the DAC with a callback function.
+ *
+ * @param topic The topic of the message.
+ * @param topic_length The length of the topic string.
+ * @param payload The payload of the message.
+ * @param payload_length The length of the payload string.
+ */
+void dac_set_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
+{
+ int a = topic[5] - '0';
+ int b = topic[6] - '0';
+ int id = 10 * a + b;
+ int value = atoi(payload);
+ dac_set_value(id, value);
+}
+/**
+ * @brief Callback function for setting the state of the DAC.
+ *
+ * This function is called when a message is received on the specified topic.
+ * It takes the topic, topic length, payload, and payload length as parameters.
+ *
+ * @param topic The topic of the received message.
+ * @param topic_length The length of the topic string.
+ * @param payload The payload of the received message.
+ * @param payload_length The length of the payload string.
+ */
+void dac_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length)
+{
+ int a = topic[5] - '0';
+ int b = topic[6] - '0';
+ int id = 10 * a + b;
+ if (!strcmp(payload, "on"))
+ {
+ dac_set_state(id, true);
+ }
+ else if (!strcmp(payload, "off"))
+ {
+ dac_set_state(id, false);
+ }
+}
+
+/**
+ * @brief Get the ADC value for the specified ID.
+ *
+ * @param id The ID of the ADC channel.
+ * @return The ADC value.
+ */
+uint16_t adc_get_value(int id)
+{
+ return adc_values[id];
+}
+/**
+ * @brief Get the state of the ADC with the specified ID.
+ *
+ * @param id The ID of the ADC.
+ * @return true if the ADC is enabled, false otherwise.
+ */
+bool adc_get_state(int id)
+{
+ return adc_report_enable[id];
+}
+/**
+ * @brief Get the value of a DAC channel.
+ *
+ * @param id The ID of the DAC channel.
+ * @return The value of the DAC channel.
+ */
+uint16_t dac_get_value(int id)
+{
+ return dac_values[id];
+}
+/**
+ * @brief Get the state of the DAC with the specified ID.
+ *
+ * @param id The ID of the DAC.
+ * @return The state of the DAC.
+ */
+bool dac_get_state(int id)
+{
+ return dac_states[id];
+}
+
+#endif
+
+void virtual_interrupt_preload()
+{
+ for (int i = 0; i < 16; i++)
+ {
+ virtual_interupt_state[i] = ESPMega_digitalRead(virtual_interrupt_pins[i]);
+ }
}
\ No newline at end of file
diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp
index f542632..fb6afc7 100644
--- a/src/espmega_iot_core.hpp
+++ b/src/espmega_iot_core.hpp
@@ -43,15 +43,16 @@
#endif
#include "espmega_iot_timer.hpp"
-void mqtt_callback(char* topic, byte* payload, unsigned int length);
+IRAM_ATTR void mqtt_callback(char* topic, byte* payload, unsigned int length);
void virtual_interrupt_loop();
void virtual_interrupt_callback(int pin, int state);
+void virtual_interrupt_preload();
void network_begin();
void mqtt_connect();
void mqtt_subscribe();
void thread_initialization();
-void pwm_state_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length);
-void pwm_value_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length);
+IRAM_ATTR void pwm_state_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length);
+IRAM_ATTR void pwm_value_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length);
void state_request_callback();
void io_begin();
void ir_loop();
@@ -60,8 +61,9 @@ void ota_begin();
void publish_pwm_states();
void publish_pwm_state(int id);
-void pwm_set_state(int id, int state);
-void pwm_set_value(int id, int value);
+void publish_pwm_value(int id);
+IRAM_ATTR void pwm_set_state(int id, int state);
+IRAM_ATTR void pwm_set_value(int id, int value);
void pwm_toggle(int id);
void pwm_toggle(int id1, int id2);
void pwm_cycle_value(int id);
@@ -104,8 +106,8 @@ void trigger13();
void trigger14();
void trigger15();
-void eeprom_retrieve_init();
-void eeprom_pwm_update();
+void fram_retrieve_init();
+void fram_pwm_update();
void lcd_ac_refresh_fan();
void lcd_ac_refresh_mode();
@@ -115,20 +117,47 @@ void set_netmask(String address);
void set_dns(String address);
void set_gw(String address);
void set_mqtt_server(String address);
-void eeprom_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4);
-IPAddress eeprom_ip_retrieve(uint16_t rom_address);
+void fram_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4);
+IPAddress fram_ip_retrieve(uint16_t rom_address);
void set_hostname(String hostname);
-void eeprom_hostname_retrieve();
+void fram_hostname_retrieve();
void set_basetopic(String topic);
-void eeprom_basetopic_retrieve();
+void fram_basetopic_retrieve();
void mqtt_port_set(uint16_t port);
-void eeprom_mqtt_port_retrieve();
-void eeprom_mqtt_username_retrieve();
-void eeprom_mqtt_password_retrieve();
+void fram_mqtt_port_retrieve();
+void fram_mqtt_username_retrieve();
+void fram_mqtt_password_retrieve();
void set_mqtt_username(String username);
void set_mqtt_password(String password);
-void eeprom_mqtt_useauth_retrieve();
+void fram_mqtt_useauth_retrieve();
void set_mqtt_useauth(bool use_auth);
void factory_reset();
-void check_boot_reset();
\ No newline at end of file
+void check_boot_reset();
+
+void enable_adc(int id);
+void disable_adc(int id);
+void adc_update(int id);
+void adc_update_force(int id);
+void adc_update_all();
+void adc_loop();
+void publish_adc_value(int id);
+void publish_adc_values();
+uint16_t get_adc_value(int id);
+void adc_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length);
+void dac_set_value(int id, int value);
+void dac_set_state(int id, bool state);
+void dac_set_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length);
+void dac_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length);
+void publish_dac_value(int id);
+void publish_dac_state(int id);
+void publish_dac_values();
+void publish_dac_states();
+void publish_adc_state(int id);
+void publish_adc_states();
+uint16_t adc_get_value(int id);
+bool adc_get_state(int id);
+uint16_t dac_get_value(int id);
+bool dac_get_state(int id);
+
+void pwm_set_publish_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length);
\ No newline at end of file
diff --git a/src/user_code.hpp b/src/user_code.hpp
index f14d89b..938316e 100644
--- a/src/user_code.hpp
+++ b/src/user_code.hpp
@@ -12,19 +12,25 @@
//#define OVERCLOCK_FM
//#define OVERCLOCK_FM2
-// Enable Software Module(s)
-#define ENABLE_INTERNAL_LCD
-#define ENABLE_IR_MODULE
-#define ENABLE_CLIMATE_MODULE // Require IR Module
-#define ENABLE_WEBUI
+// I/O Configuration
+#define VIRTUAL_INTERRUPT_PRELOAD // Preload Virtual Interrupts buffer
-// Infrared Transciever
+// Enable Software Module(s)
+// Deprecated. Use Build Flags instead.
+// #define ENABLE_INTERNAL_LCD
+// #define ENABLE_IR_MODULE
+// #define ENABLE_CLIMATE_MODULE // Require IR Module
+// #define ENABLE_ANALOG_MODULE
+// #define ENABLE_WEBUI
+
+// IR Kit Configuration
#define IR_RECIEVE_PIN 35
#define IR_SEND_PIN 17
#define MARK_EXCESS_MICROS 20
-#define RAW_BUFFER_LENGTH 750
+#define IR_RAW_BUFFER_LENGTH 750
#define AC_MAX_TEMPERATURE 30
#define AC_MIN_TEMPERATURE 15
+#define DHT22_PIN 32
// External LCD Configuration
#define ENABLE_EXTERNAL_LCD
@@ -35,19 +41,24 @@
#define ESPMega_EXTLCD Serial2
#endif
+// Analog Module Configuration
+#define ANALOG_REPORTING_INTERVAL 500
+
// User Defined Functions
+void timer1_callback();
+void bt0PopCallback(void *ptr);
+
+// User Defined IoT Core Callback Functions (Required)
+void user_mqtt_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length);
+void user_state_request_callback();
+void mqtt_connected_user_callback();
void user_pre_init();
void user_init();
void user_loop();
-void virtual_interrupt_user_callback(int pin, int state);
void pwm_changed_user_callback(int pin);
void ac_changed_user_callback(int mode, int temperature, int fan_speed);
void timer_tick_callback();
-void timer1_callback();
-void mqtt_connected_user_callback();
-void bt0PopCallback(void *ptr);
-void user_state_request_callback();
-void user_mqtt_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length);
+void virtual_interrupt_user_callback(int pin, int state);
// ESPMega IoT Core Build-in Functions
extern void pwm_set_state(int id, int state);
@@ -59,9 +70,26 @@ extern bool pwm_get_state(int id);
extern uint16_t pwm_get_value(int id);
extern boolean pwm_group_state(int id1, int id2);
extern bool input_get_state(int id);
+extern bool standalone;
+extern PubSubClient mqtt;
+
+// IR Kit Build-in Functions
+#ifdef ENABLE_IR_MODULE
extern void ac_set_state(int mode, int temperature, int fan_speed);
extern uint8_t ac_get_temperature();
extern uint8_t ac_get_mode();
extern uint8_t ac_get_fan_speed();
-extern bool standalone;
-extern PubSubClient mqtt;
\ No newline at end of file
+#endif
+
+//Analog Expansion Card Build-in Functions
+#ifdef ENABLE_ANALOG_MODULE
+extern void dac_set_value(int id, int value);
+extern void dac_set_state(int id, bool state);
+extern void enable_adc(int id);
+extern void disable_adc(int id);
+extern void enable_dac(int id);
+extern uint16_t adc_get_value(int id);
+extern bool adc_get_state(int id);
+extern uint16_t dac_get_value(int id);
+extern bool dac_get_state(int id);
+#endif
\ No newline at end of file