diff --git a/.gitignore b/.gitignore index a4a37ad..8a9fb2f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,4 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch -.vs/ -.vscode/ -.vscode/settings.json -firmware/ -release/ \ No newline at end of file +.vs/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index ee32b37..69aa100 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,78 +1,20 @@ { - "C_Cpp.errorSquiggles": "enabled", - "files.associations": { - "*.cps": "javascript", - "string": "cpp", - "optional": "cpp", - "istream": "cpp", - "ostream": "cpp", - "system_error": "cpp", - "array": "cpp", - "functional": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "*.d": "cpp", - "*.html": "cpp", - "*.tcc": "cpp", - "regex": "cpp" - }, - "C_Cpp_Runner.msvcBatchPath": "", - "C_Cpp_Runner.cCompilerPath": "gcc", - "C_Cpp_Runner.cppCompilerPath": "g++", - "C_Cpp_Runner.debuggerPath": "gdb", - "C_Cpp_Runner.cStandard": "", - "C_Cpp_Runner.cppStandard": "", - "C_Cpp_Runner.useMsvc": false, - "C_Cpp_Runner.warnings": [ - "-Wall", - "-Wextra", - "-Wpedantic", - "-Wshadow", - "-Wformat=2", - "-Wcast-align", - "-Wconversion", - "-Wsign-conversion", - "-Wnull-dereference" - ], - "C_Cpp_Runner.msvcWarnings": [ - "/W4", - "/permissive-", - "/w14242", - "/w14287", - "/w14296", - "/w14311", - "/w14826", - "/w44062", - "/w44242", - "/w14905", - "/w14906", - "/w14263", - "/w44265", - "/w14928" - ], - "C_Cpp_Runner.enableWarnings": true, - "C_Cpp_Runner.warningsAsError": false, - "C_Cpp_Runner.compilerArgs": [], - "C_Cpp_Runner.linkerArgs": [], - "C_Cpp_Runner.includePaths": [], - "C_Cpp_Runner.includeSearch": [ - "*", - "**/*" - ], - "C_Cpp_Runner.excludeSearch": [ - "**/build", - "**/build/**", - "**/.*", - "**/.*/**", - "**/.vscode", - "**/.vscode/**" - ], - "C_Cpp_Runner.useAddressSanitizer": false, - "C_Cpp_Runner.useUndefinedSanitizer": false, - "C_Cpp_Runner.useLeakSanitizer": false, - "C_Cpp_Runner.showCompilationTime": false, - "C_Cpp_Runner.useLinkTimeOptimization": false, - "C_Cpp_Runner.msvcSecureNoWarnings": false, - "cmake.sourceDirectory": "D:/Git/iot-firmware/.pio/libdeps/full/Adafruit BusIO" + "C_Cpp.errorSquiggles": "enabled", + "files.associations": { + "*.cps": "javascript", + "string": "cpp", + "optional": "cpp", + "istream": "cpp", + "ostream": "cpp", + "system_error": "cpp", + "array": "cpp", + "functional": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "*.d": "cpp", + "*.html": "cpp", + "*.tcc": "cpp", + "regex": "cpp" + } } \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index dcf9353..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,20 +0,0 @@ -pipeline { - agent any - - stages { - stage('Build') { - steps { - git branch: 'main', 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 deleted file mode 100644 index 2c07d5e..0000000 --- a/gen_release.py +++ /dev/null @@ -1,115 +0,0 @@ -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/platformio.ini b/platformio.ini index da29e98..0074e59 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,15 +8,10 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[platformio] -build_dir = firmware - -[env:full] +[env:wt32-eth01] 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 @@ -27,145 +22,4 @@ lib_deps = siwats/ESPMegaPROR3@^1.3.0 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 -board_build.f_cpu = 240000000L -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 \ No newline at end of file +monitor_speed = 115200 \ No newline at end of file diff --git a/readme.md b/readme.md deleted file mode 100644 index b0a4f7e..0000000 --- a/readme.md +++ /dev/null @@ -1,35 +0,0 @@ -# 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 0472888..84e0817 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -1,15 +1,3 @@ -/** - * @file espmega_iot_core.cpp - * @brief Implementation of the ESPMega IoT Core library. - * - * This library provides the core functionality for the ESPMega IoT platform, including network connectivity, - * input/output control, and MQTT communication. It also includes support for an internal LCD display and - * air conditioner control. - * - * @author Siwat Sirichai - * @date 15 Nov 2023 - */ - #include // OS Configuration @@ -31,23 +19,18 @@ uint16_t MQTT_PORT = 0; WebServer otaserver(80); #endif bool standalone = true; +// #define MQTT_BASE_TOPIC "/espmega/ProR3" 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 @@ -60,9 +43,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_fram[PWM_COUNT]; +uint8_t pwm_states_eeprom[PWM_COUNT]; uint16_t pwm_values[PWM_COUNT]; -uint8_t pwm_values_fram[PWM_COUNT * 2]; +uint8_t pwm_values_eeprom[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}; @@ -70,7 +53,6 @@ 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 @@ -85,6 +67,7 @@ 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; @@ -98,57 +81,31 @@ char AC_ROOM_TEMPERATURE_TOPIC[75]; char AC_HUMIDITY_TOPIC[75]; #endif -#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 +// 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 char PWM_STATE_TOPIC[75]; char PWM_VALUE_TOPIC[75]; char INPUTS_TOPIC[75]; WiFiClient eth; -PubSubClient mqtt(MQTT_SERVER, 1883, eth); +PubSubClient mqtt_client(MQTT_SERVER, 1883, eth); +PubSubClientTools mqtt(mqtt_client); #ifdef ENABLE_CLIMATE_MODULE DHTNEW env_sensor(DHT22_PIN); @@ -156,10 +113,9 @@ DHTNEW env_sensor(DHT22_PIN); Thread mqtt_reconnector = Thread(); Thread environment_reporter = Thread(); -Thread fram_pwm_updater = Thread(); +Thread eeprom_pwm_updater = Thread(); Thread user_timer_tick = Thread(); -Thread analog_handler = Thread(); -StaticThreadController<5> thread_controller(&mqtt_reconnector, &environment_reporter, &fram_pwm_updater, &user_timer_tick, &analog_handler); +StaticThreadController<4> thread_controller(&mqtt_reconnector, &environment_reporter, &eeprom_pwm_updater, &user_timer_tick); #ifdef ENABLE_INTERNAL_LCD Thread top_bar_updater = Thread(); @@ -178,17 +134,8 @@ void setup() #endif Serial.println("ESPMega R3 Initializing"); ESPMega_begin(); -#ifdef OVERCLOCK_FM2 - Wire.setClock(1000000); -#endif -#ifdef OVERCLOCK_FM - Wire.setClock(400000); -#endif io_begin(); -#ifdef VIRTUAL_INTERRUPT_PRELOAD - virtual_interrupt_preload(); -#endif - fram_retrieve_init(); + eeprom_retrieve_init(); user_pre_init(); #ifdef ENABLE_INTERNAL_LCD lcd_send_stop_bit(); @@ -212,9 +159,8 @@ void setup() lcd_send_command("boot_state.txt=\"Network Initializing . . .\""); network_begin(); lcd_send_command("boot_state.txt=\"IoT Core Initializing . . .\""); - mqtt.setSocketTimeout(1000); + mqtt_client.setSocketTimeout(1000); eth.setTimeout(1); - mqtt.setCallback(&mqtt_callback); mqtt_connect(); lcd_send_command("boot_state.txt=\"Threads Initializing . . .\""); thread_initialization(); @@ -230,7 +176,7 @@ void setup() void loop() { virtual_interrupt_loop(); - mqtt.loop(); + mqtt_client.loop(); ESPMega_loop(); #ifdef ENABLE_IR_MODULE ir_loop(); @@ -245,55 +191,37 @@ void loop() #endif } -/** - * @brief Retrieves data from FRAM and initializes various variables and topics. - * - */ -void fram_retrieve_init() +void eeprom_retrieve_init() { -#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 -// FRAM Data Retrival +// EEPROM 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); + 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); #endif -// FRAM Data Retrival Validation +// EEPROM Data Retrival Validation #ifdef ENABLE_CLIMATE_MODULE if (ac_mode > 2) { ac_mode = 0; - ESPMega_FRAM.write8(FRAM_ADDRESS_AC_MODE, ac_mode); + ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_MODE, ac_mode); } if (ac_temperature > AC_MAX_TEMPERATURE || ac_temperature < AC_MIN_TEMPERATURE) { ac_temperature = AC_MAX_TEMPERATURE; - ESPMega_FRAM.write8(FRAM_ADDRESS_AC_TEMPERATURE, ac_temperature); + ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_temperature); } if (ac_fan_speed > 3) { ac_fan_speed = 0; - ESPMega_FRAM.write8(FRAM_ADDRESS_AC_TEMPERATURE, ac_fan_speed); + ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_fan_speed); } ac_set_state(ac_mode, ac_temperature, ac_fan_speed); #endif - 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); + 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); for (int i = 0; i < 15; i++) { if (pwm_states[i] <= 1) @@ -305,18 +233,18 @@ void fram_retrieve_init() else pwm_set_value(i, 0); } - 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); - fram_basetopic_retrieve(); + 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(); + mqtt_client.setServer(MQTT_SERVER, MQTT_PORT); + eeprom_basetopic_retrieve(); base_topic_length = strlen(MQTT_BASE_TOPIC) + 1; memcpy(STATE_REQUEST_TOPIC, MQTT_BASE_TOPIC, 20); strcat(STATE_REQUEST_TOPIC, "/requeststate"); @@ -324,8 +252,6 @@ void fram_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"); @@ -350,62 +276,19 @@ void fram_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 -/** - * Initializes the OTA (Over-The-Air) update server and sets up the necessary routes for configuration and firmware updates. - * - * The OTA server can be accessed through the root URL ("/") and the configuration page can be accessed through "/config". - * The firmware update can be initiated through the "/update" route using HTTP POST method. - * - * The configuration page allows the user to set the device IP address, network mask, gateway, DNS server, hostname, BMS server IP address, BMS server port, BMS server endpoint, and BMS server authentication credentials. - * - * @return void - */ 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; @@ -417,8 +300,6 @@ 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; @@ -432,15 +313,11 @@ 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); @@ -473,10 +350,6 @@ 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); @@ -487,8 +360,6 @@ 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(); }, @@ -566,14 +437,6 @@ void io_begin() #endif } -/** - * @brief Initializes the network and sets the hostname and IP configuration. - * - * @details This function initializes the Ethernet connection and sets the hostname, IP address, gateway, subnet, and DNS server. - * It also initializes the NTP core and updates the time from the NTP server. - * - * @return void - */ void network_begin() { Serial.print("Initializing Network "); @@ -600,32 +463,20 @@ void network_begin() Serial.println(); } -/** - * @brief Connects to the MQTT broker and subscribes to topics. - * - * If MQTT_USE_AUTH is true, it connects to the broker using the provided username and password. - * If the connection is successful, it subscribes to topics and publishes PWM and input states. - * If ENABLE_CLIMATE_MODULE is defined, it also publishes AC state. - * - * @note This function assumes that the MQTT client has been initialized and WiFi is connected. - * - * @return void - */ void mqtt_connect() { - if (!mqtt.connected()) + if (!mqtt_client.connected()) { Serial.print("MQTT not connected, connecting . . .\n"); lcd_send_stop_bit(); if (MQTT_USE_AUTH) - mqtt.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD, AVAILABILITY_TOPIC, 0, true, "offline"); + mqtt_client.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD); else - mqtt.connect(HOSTNAME, AVAILABILITY_TOPIC, 0, true, "offline"); - if (mqtt.connected()) + mqtt_client.connect(HOSTNAME); + if (mqtt_client.connected()) { mqtt_subscribe(); Serial.print("MQTT connected\n"); - mqtt.publish(AVAILABILITY_TOPIC, "online", true); lcd_send_stop_bit(); publish_pwm_states(); publish_input_states(); @@ -633,12 +484,6 @@ 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(); } @@ -656,10 +501,6 @@ void mqtt_connect() } } -/** - * @brief Subscribes to MQTT topics for controlling PWM, climate module and requesting device state. - * - */ void mqtt_subscribe() { for (int i = 0; i < PWM_COUNT; i++) @@ -668,106 +509,17 @@ void mqtt_subscribe() PWM_SET_VALUE_TOPIC[base_topic_length + 5] = (i % 10) + '0'; PWM_SET_STATE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0'; PWM_SET_STATE_TOPIC[base_topic_length + 5] = (i % 10) + '0'; - mqtt.subscribe(PWM_SET_STATE_TOPIC); - mqtt.subscribe(PWM_SET_VALUE_TOPIC); + mqtt.subscribe(PWM_SET_STATE_TOPIC, pwm_state_callback); + mqtt.subscribe(PWM_SET_VALUE_TOPIC, pwm_value_callback); } - 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); - } + mqtt.subscribe(AC_SET_FAN_TOPIC, ac_state_callback); + mqtt.subscribe(AC_SET_TEMPERATURE_TOPIC, ac_state_callback); + mqtt.subscribe(AC_SET_MODE_TOPIC, ac_state_callback); #endif + mqtt.subscribe(STATE_REQUEST_TOPIC, state_request_callback); } -/** - * @brief Callback function for MQTT messages received by the device. - * - * @param topic The topic of the received message. - * @param payload The payload of the received message. - * @param length The length of the payload. - */ -IRAM_ATTR void mqtt_callback(char *topic, byte *payload, unsigned int length) -{ - uint8_t topic_length = strlen(topic); - char topic_trim[50]; - char payload_nt[length + 1]; - memcpy(payload_nt, payload, length); - payload_nt[length] = NULL; - strncpy(topic_trim, topic + base_topic_length - 1, topic_length); - if ((!strncmp(topic_trim, "/pwm/", 5)) && !strncmp(topic_trim + 7, "/set/state", 10)) - { - pwm_state_callback(topic_trim, topic_length, payload_nt, length); - } - else if ((!strncmp(topic_trim, "/pwm/", 5)) && !strncmp(topic_trim + 7, "/set/value", 10)) - { - 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(); - } - else - { -#ifdef ENABLE_CLIMATE_MODULE - ac_state_callback(topic, topic_length, payload_nt, length); -#endif - } - user_mqtt_callback(topic, topic_length, payload_nt, length); -} - -/** - * @brief Initializes the threads for various tasks such as MQTT connection, environment reporting, FRAM PWM update, and user timer tick. - * - */ void thread_initialization() { Serial.println("Initializing Threads . . ."); @@ -778,68 +530,36 @@ void thread_initialization() environment_reporter.onRun(publish_env_state); environment_reporter.setInterval(5000); #endif - fram_pwm_updater.onRun(fram_pwm_update); - fram_pwm_updater.setInterval(1000); + eeprom_pwm_updater.onRun(eeprom_pwm_update); + eeprom_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 } -/** - * @brief Callback function for handling PWM state changes. - * - * @param topic The MQTT topic on which the message was received. - * @param topic_length The length of the MQTT topic. - * @param payload The message payload. - * @param payload_length The length of the message payload. - */ -IRAM_ATTR void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) +void pwm_state_callback(String topic, String message) { - int a = topic[5] - '0'; - int b = topic[6] - '0'; + int a = topic.charAt(base_topic_length + 4) - '0'; + int b = topic.charAt(base_topic_length + 5) - '0'; int id = 10 * a + b; - if (!strcmp(payload, "on")) + if (message.compareTo("on") == 0) { pwm_set_state(id, true); } - else if (!strcmp(payload, "off")) + else if (message.compareTo("off") == 0) { pwm_set_state(id, false); } } -/** - * @brief Callback function for PWM value updates. - * - * This function is called whenever a message is received on the PWM value update topic. - * It extracts the PWM ID and value from the topic and payload, respectively, and sets the PWM value. - * - * @param topic The topic on which the message was received. - * @param topic_length The length of the topic. - * @param payload The message payload. - * @param payload_length The length of the message payload. - */ -IRAM_ATTR void pwm_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) +void pwm_value_callback(String topic, String message) { - int a = topic[5] - '0'; - int b = topic[6] - '0'; + int a = topic.charAt(base_topic_length + 4) - '0'; + int b = topic.charAt(base_topic_length + 5) - '0'; int id = 10 * a + b; - int value = atoi(payload); + int value = message.toInt(); pwm_set_value(id, value); } -/** - * @brief Callback function for virtual interrupts. - * - * This function publishes the input state of the virtual interrupt pin and calls the user-defined callback function. - * If ENABLE_INTERNAL_LCD is defined, it also updates the LCD display with the input state. - * - * @param pin The virtual interrupt pin number. - * @param state The state of the virtual interrupt pin (HIGH or LOW). - */ void virtual_interrupt_callback(int pin, int state) { @@ -872,60 +592,34 @@ void virtual_interrupt_loop() } } -/** - * @brief Publishes the current state of all PWM channels. - * - */ void publish_pwm_states() { for (int i = 0; i < PWM_COUNT; i++) { publish_pwm_state(i); - publish_pwm_value(i); } } -/** - * @brief Publishes the state and value of a PWM signal to MQTT broker. - * - * @param id The ID of the PWM signal. - */ 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"); + mqtt_client.publish(PWM_STATE_TOPIC, "on"); } else if (state == 0) { - mqtt.publish(PWM_STATE_TOPIC, "off"); + mqtt_client.publish(PWM_STATE_TOPIC, "off"); } + mqtt.publish(String(PWM_VALUE_TOPIC), String(value)); } -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); -} - -/** - * @brief Sets the state of a PWM pin and publishes the new state. - * - * @param id The ID of the PWM pin. - * @param state The new state of the PWM pin. - */ -IRAM_ATTR void pwm_set_state(int id, int state) +void pwm_set_state(int id, int state) { if (state != pwm_states[id]) { @@ -943,13 +637,7 @@ IRAM_ATTR void pwm_set_state(int id, int state) } } -/** - * @brief Sets the PWM value for a given id. - * - * @param id The id of the PWM pin. - * @param value The value to set the PWM pin to. - */ -IRAM_ATTR void pwm_set_value(int id, int value) +void pwm_set_value(int id, int value) { pwm_values[id] = value; int pwm_state = pwm_states[id]; @@ -960,26 +648,16 @@ IRAM_ATTR 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_value(id); + publish_pwm_state(id); pwm_changed_user_callback(id); } -/** - * @brief Toggles the state of a PWM pin. - * - * @param id The ID of the PWM pin to toggle. - */ void pwm_toggle(int id) { int state = !pwm_states[id]; pwm_set_state(id, state); } -/** - * Toggles the state of two PWM pins. - * @param id1 The first PWM pin ID. - * @param id2 The second PWM pin ID. - */ void pwm_toggle(int id1, int id2) { boolean state = pwm_group_state(id1, id2); @@ -995,13 +673,6 @@ void pwm_toggle(int id1, int id2) } } -/** - * @brief Returns a boolean value indicating whether either of the two specified PWM states is true. - * - * @param id1 The first PWM state ID. - * @param id2 The second PWM state ID. - * @return true if either of the two specified PWM states is true, false otherwise. - */ boolean pwm_group_state(int id1, int id2) { int state1 = pwm_states[id1 - 1], state2 = pwm_states[id2 - 1]; @@ -1010,11 +681,6 @@ boolean pwm_group_state(int id1, int id2) return false; } -/** - * @brief Cycles the PWM value for the given id. - * - * @param id The id of the PWM pin. - */ void pwm_cycle_value(int id) { int state = pwm_states[id]; @@ -1040,10 +706,6 @@ void pwm_cycle_value(int id) pwm_set_value(id, PWM_CYCLE_VALUES[PWM_CYCLE_VALUES_COUNT - 1]); } -/** - * @brief Publishes the input states for all virtual input pins. - * - */ void publish_input_states() { for (int i = 0; i < VINT_COUNT; i++) @@ -1051,58 +713,27 @@ void publish_input_states() publish_input_state(i); } } - -/** - * @brief Publishes the input state of a specific pin. - * - * @param id The ID of the pin to publish the state of. - */ void publish_input_state(int id) { int state = ESPMega_digitalRead(virtual_interrupt_pins[id]); publish_input_state(id, state); } -/** - * @brief Publishes the state of an input to the MQTT broker. - * - * @param id The ID of the input. - * @param state The state of the input (0 or 1). - */ void publish_input_state(int id, int state) { INPUTS_TOPIC[base_topic_length + 6] = ((id - id % 10) / 10) + '0'; INPUTS_TOPIC[base_topic_length + 7] = (id % 10) + '0'; - mqtt.publish(INPUTS_TOPIC, state ? "1" : "0"); + mqtt.publish(String(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. - * - * This function publishes the input and PWM states of the device. If the climate module is enabled, it also publishes the AC and environment states. - * Finally, it calls the user-defined state request callback function. - */ -void state_request_callback() +void state_request_callback(String topic, String message) { 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 @@ -1116,109 +747,88 @@ void ir_loop() #endif #ifdef ENABLE_CLIMATE_MODULE -/** - * @brief Publishes the current state of the air conditioner to MQTT topics. - * - */ void publish_ac_state() { + String temp = ""; switch (ac_mode) { case 0: - mqtt.publish(AC_MODE_TOPIC, "off"); + temp = "off"; break; case 1: - mqtt.publish(AC_MODE_TOPIC, "cool"); + temp = "cool"; break; case 2: - mqtt.publish(AC_MODE_TOPIC, "fan_only"); + temp = "fan_only"; default: break; } - char temp[5]; - itoa(ac_temperature, temp, DEC); - mqtt.publish(AC_TEMPERATURE_TOPIC, temp); + mqtt.publish(String(AC_MODE_TOPIC), temp); + mqtt.publish(String(AC_TEMPERATURE_TOPIC), String(ac_temperature)); switch (ac_fan_speed) { case 0: - mqtt.publish(AC_FAN_TOPIC, "auto"); + temp = "auto"; break; case 1: - mqtt.publish(AC_FAN_TOPIC, "high"); + temp = "high"; break; case 2: - mqtt.publish(AC_FAN_TOPIC, "medium"); + temp = "med"; break; case 3: - mqtt.publish(AC_FAN_TOPIC, "low"); + temp = "low"; break; } + mqtt.publish(String(AC_FAN_TOPIC), temp); } -/** - * @brief Callback function for handling AC state changes. - * - * This function is called whenever a message is received on the AC_SET_TEMPERATURE_TOPIC, AC_SET_MODE_TOPIC, or AC_SET_FAN_TOPIC. - * It parses the payload of the message and updates the AC state accordingly. - * - * @param topic The topic of the message. - * @param topic_length The length of the topic. - * @param payload The payload of the message. - * @param payload_length The length of the payload. - */ -void ac_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) +void ac_state_callback(String topic, String message) { - if (!strcmp(topic, AC_SET_TEMPERATURE_TOPIC)) + if (topic.compareTo(String(AC_SET_TEMPERATURE_TOPIC)) == 0) { - int new_temp = atoi(payload); + int new_temp = message.toInt(); if (new_temp >= AC_MIN_TEMPERATURE && new_temp <= AC_MAX_TEMPERATURE) { ac_set_state(ac_mode, new_temp, ac_fan_speed); } } - else if (!strcmp(topic, AC_SET_MODE_TOPIC)) + else if (topic.compareTo(String(AC_SET_MODE_TOPIC)) == 0) { - if (!strcmp(payload, "off")) + if (message.compareTo("off") == 0) { ac_set_state(0, ac_temperature, ac_fan_speed); } - else if (!strcmp(payload, "cool")) + else if (message.compareTo("cool") == 0) { ac_set_state(1, ac_temperature, ac_fan_speed); } - else if (!strcmp(payload, "fan_only")) + else if (message.compareTo("fan_only") == 0) { ac_set_state(2, ac_temperature, ac_fan_speed); } } - else if (!strcmp(topic, AC_SET_FAN_TOPIC)) + else if (topic.compareTo(String(AC_SET_FAN_TOPIC)) == 0) { - if (!strcmp(payload, "auto")) + if (message.compareTo("auto") == 0) { ac_set_state(ac_mode, ac_temperature, 0); } - else if (!strcmp(payload, "high")) + else if (message.compareTo("low") == 0) { ac_set_state(ac_mode, ac_temperature, 1); } - else if (!strcmp(payload, "medium")) + else if (message.compareTo("med") == 0) { ac_set_state(ac_mode, ac_temperature, 2); } - else if (!strcmp(payload, "low")) + else if (message.compareTo("high") == 0) { ac_set_state(ac_mode, ac_temperature, 3); } } } -/** - * @brief Sets the state of the air conditioner. - * - * @param mode The mode of the air conditioner (0 = off, 1 = cool, 2 = fan). - * @param temperature The temperature to set the air conditioner to (in Celsius). - * @param fan_speed The fan speed of the air conditioner (0 = low, 1 = medium, 2 = high). - */ void ac_set_state(int mode, int temperature, int fan_speed) { ac_mode = mode; @@ -1249,7 +859,7 @@ void ac_set_state(int mode, int temperature, int fan_speed) IrSender.sendRaw(ir_code_off, sizeof(ir_code_off) / sizeof(ir_code_off[0]), NEC_KHZ); break; case 1: - IrSender.sendRaw(ir_code_cool[fan_speed][temperature], sizeof(ir_code_cool[fan_speed][temperature]) / sizeof(ir_code_cool[fan_speed][temperature][0]), NEC_KHZ); + IrSender.sendRaw(ir_code_cool[fan_speed][temperature], sizeof(ir_code_cool[fan_speed][temperature]) / sizeof(ir_code_cool[fan_speed][0]), NEC_KHZ); break; case 2: IrSender.sendRaw(ir_code_fan[fan_speed], sizeof(ir_code_fan[fan_speed]) / sizeof(ir_code_fan[fan_speed][0]), NEC_KHZ); @@ -1258,18 +868,8 @@ void ac_set_state(int mode, int temperature, int fan_speed) ac_changed_user_callback(mode, ac_temperature, fan_speed); } -/** - * @brief Reads the environment sensor and publishes the temperature and humidity to MQTT topics. - * - * @details Reads the environment sensor and publishes the temperature and humidity to MQTT topics. - * If the internal LCD is enabled, it also updates the temperature and humidity values on the LCD screen. - * - * @return void - */ void publish_env_state() { - if(!pwm_report_enable) - return; int errorCode = env_sensor.read(); yield(); switch (errorCode) @@ -1277,12 +877,10 @@ void publish_env_state() case DHTLIB_OK: current_room_humid = env_sensor.getHumidity(); current_room_temp = env_sensor.getTemperature(); - char temp[5]; - dtostrf(current_room_temp, 0, 2, temp); - mqtt.publish(AC_ROOM_TEMPERATURE_TOPIC, temp); - dtostrf(current_room_humid, 0, 2, temp); - mqtt.publish(AC_HUMIDITY_TOPIC, temp); - mqtt.loop(); + mqtt.publish(String(AC_ROOM_TEMPERATURE_TOPIC), String(current_room_temp)); + mqtt_client.loop(); + mqtt.publish(String(AC_HUMIDITY_TOPIC), String(current_room_humid)); + mqtt_client.loop(); #ifdef ENABLE_INTERNAL_LCD if (lcd_current_page == 4) { @@ -1294,19 +892,15 @@ void publish_env_state() #endif break; default: - mqtt.publish(AC_ROOM_TEMPERATURE_TOPIC, "ERROR"); - mqtt.loop(); - mqtt.publish(AC_HUMIDITY_TOPIC, "ERROR"); - mqtt.loop(); + mqtt.publish(String(AC_ROOM_TEMPERATURE_TOPIC), "ERROR"); + mqtt_client.loop(); + mqtt.publish(String(AC_HUMIDITY_TOPIC), "ERROR"); + mqtt_client.loop(); } } #endif #ifdef ENABLE_INTERNAL_LCD -/** - * @brief Initializes the LCD display and sets up the refresh intervals for the top bar and page. - * - */ void lcd_begin() { top_bar_updater.onRun(lcd_top_bar_update); @@ -1316,10 +910,6 @@ void lcd_begin() lcd_refresh(); } -/** - * @brief Runs the LCD loop, updating the display and listening for input. - * - */ void lcd_loop() { lcd_thread_controller.run(); @@ -1332,10 +922,6 @@ void lcd_loop() } } -/** - * @brief Refreshes the LCD display if the current page is 1. - * - */ void lcd_refresh_pd() { if (lcd_current_page == 1) @@ -1344,14 +930,6 @@ void lcd_refresh_pd() } } -/** - * @brief Refreshes the LCD display based on the current page. - * - * @details The function writes the appropriate values to the LCD display based on the current page. - * - * @note This function assumes that the LCD panel has already been initialized. - * - */ void lcd_refresh() { switch (lcd_current_page) @@ -1414,15 +992,6 @@ void lcd_refresh() break; } } - -/** - * @brief Updates the top bar of the LCD display with the current time, server status, and LAN status. - * - * @details This function gets the current time using ESPMega_getTime() function and formats it to display on the LCD. - * It also updates the server and LAN status icons based on the standalone and ETH.linkUp() values respectively. - * - * @return void - */ void lcd_top_bar_update() { char time_buffer[15]; @@ -1432,18 +1001,7 @@ void lcd_top_bar_update() panel.writeNum("server.pic", standalone ? 4 : 5); panel.writeNum("lan.pic", ETH.linkUp() ? 3 : 2); } - #ifdef ENABLE_CLIMATE_MODULE -/** - * @brief Refreshes the LCD display with the current AC mode. - * - * This function updates the LCD display with the current AC mode, which can be one of the following: - * - 0: Off - * - 1: Cool - * - 2: Fan - * - * The function uses the panel object to write the appropriate image to the display for each mode. - */ void lcd_ac_refresh_mode() { // auto high mid low @@ -1452,13 +1010,6 @@ void lcd_ac_refresh_mode() panel.writeNum("mode_off.pic", ac_mode == 0 ? 24 : 25); } -/** - * @brief Refreshes the fan speed icons on the LCD panel based on the current AC fan speed. - * - * This function updates the fan speed icons on the LCD panel based on the current AC fan speed. - * It uses the panel.writeNum() function to write the appropriate fan speed icon to the panel. - * - */ void lcd_ac_refresh_fan() { panel.writeNum("fan_auto.pic", ac_fan_speed == 0 ? 14 : 15); @@ -1592,306 +1143,152 @@ void trigger15() } #endif // End Internal LCD Code Block -/** - * @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 FRAM, - * this function updates the FRAM with the current values. - */ -void fram_pwm_update() +void eeprom_pwm_update() { - if (memcmp(pwm_states, pwm_states_fram, 16)) + if (memcmp(pwm_states, pwm_states_eeprom, 16)) { - memcpy(pwm_states_fram, pwm_states, 16); - ESPMega_FRAM.write(3, pwm_states_fram, 16); + memcpy(pwm_states_eeprom, pwm_states, 16); + ESPMega_FRAM.write(3, pwm_states_eeprom, 16); + lcd_send_stop_bit(); } - if (memcmp(pwm_values, pwm_values_fram, 32)) + if (memcmp(pwm_values, pwm_values_eeprom, 32)) { - memcpy(pwm_values_fram, pwm_values, 32); - ESPMega_FRAM.write(19, pwm_values_fram, 32); + memcpy(pwm_values_eeprom, pwm_values, 32); + ESPMega_FRAM.write(19, pwm_values_eeprom, 32); + lcd_send_stop_bit(); } } -/** - * @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); - fram_ip_update(FRAM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]); + eeprom_ip_update(EEPROM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]); } - -/** - * @brief Sets the subnet mask for the device. - * - * @param address The subnet mask address to set. - */ void set_netmask(String address) { SUBNET.fromString(address); - fram_ip_update(FRAM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]); + eeprom_ip_update(EEPROM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]); } - -/** - * Sets the DNS server address. - * @param address The IP address of the DNS server. - */ void set_dns(String address) { DNS.fromString(address); - fram_ip_update(FRAM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]); + eeprom_ip_update(EEPROM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]); } - -/** - * @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); - fram_ip_update(FRAM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]); + eeprom_ip_update(EEPROM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]); } - -/** - * @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); - fram_ip_update(FRAM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]); + eeprom_ip_update(EEPROM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]); } - -/** - * @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. - * @param byte2 The second byte of the IP address. - * @param byte3 The third byte of the IP address. - * @param byte4 The fourth byte of the IP address. - */ -void fram_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) +void eeprom_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 FRAM memory. - * - * @param rom_address The address in FRAM memory where the IP address is stored. - * @return The retrieved IP address. - */ -IPAddress fram_ip_retrieve(uint16_t rom_address) +IPAddress eeprom_ip_retrieve(uint16_t rom_address) { uint8_t addressblock[4]; ESPMega_FRAM.read(rom_address, addressblock, 4); return IPAddress(addressblock[0], addressblock[1], addressblock[2], addressblock[3]); } -/** - * @brief Sets the hostname for the device and writes it to non-volatile memory. - * - * @param hostname The hostname to set. - */ void set_hostname(String hostname) { hostname.toCharArray(HOSTNAME, 15); - ESPMega_FRAM.write(FRAM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); + ESPMega_FRAM.write(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } -/** - * @brief Retrieves the hostname from FRAM and stores it in the HOSTNAME variable. - * - */ -void fram_hostname_retrieve() +void eeprom_hostname_retrieve() { - ESPMega_FRAM.read(FRAM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); + ESPMega_FRAM.read(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } -/** - * @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(FRAM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); + ESPMega_FRAM.write(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } -/** - * @brief Retrieves the MQTT base topic from FRAM and stores it in MQTT_BASE_TOPIC array. - * - */ -void fram_basetopic_retrieve() +void eeprom_basetopic_retrieve() { - ESPMega_FRAM.read(FRAM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); + ESPMega_FRAM.read(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } -/** - * @brief Sets the MQTT port in the FRAM. - * - * @param port The MQTT port to be set. - */ void mqtt_port_set(uint16_t port) { uint8_t port_arr[2]; memcpy(port_arr, &port, 2); - ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_PORT, port_arr, 2); + ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); } -/** - * @brief Retrieves the MQTT port from FRAM and stores it in the MQTT_PORT variable. - * - */ -void fram_mqtt_port_retrieve() +void eeprom_mqtt_port_retrieve() { uint8_t port_arr[2]; - ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_PORT, port_arr, 2); + ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); memcpy(&MQTT_PORT, port_arr, 2); } -/** - * @brief Returns the state of the PWM with the given ID. - * - * @param id The ID of the PWM. - * @return true if the PWM is on, false otherwise. - */ boolean pwm_get_state(int id) { return pwm_states[id]; } -/** - * Returns the current PWM value for the specified ID. - * - * @param id The ID of the PWM channel to get the value for. - * @return The current PWM value for the specified ID. - */ uint16_t pwm_get_value(int id) { return pwm_values[id]; } -/** - * @brief Returns the state of the virtual interrupt with the given ID. - * - * @param id The ID of the virtual interrupt. - * @return The state of the virtual interrupt. - */ boolean input_get_state(int id) { return virtual_interupt_state[id]; } #ifdef ENABLE_CLIMATE_MODULE -/** - * @brief Returns the current temperature value. - * - * @return The current temperature value. - */ uint8_t ac_get_temperature() { return ac_temperature; } -/** - * @brief Get the current mode of the AC system. - * - * @return uint8_t The current mode of the AC system. - */ uint8_t ac_get_mode() { return ac_mode; } -/** - * @brief Get the current fan speed. - * - * @return uint8_t The current fan speed. - */ uint8_t ac_get_fan_speed() { return ac_fan_speed; } #endif -/** - * @brief Retrieves the MQTT username from FRAM and stores it in the MQTT_USERNAME global variable. - * - */ -void fram_mqtt_username_retrieve() +void eeprom_mqtt_username_retrieve() { - ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32); + ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32); } -/** - * @brief Retrieves the MQTT password from FRAM and stores it in the MQTT_PASSWORD global variable. - * - */ -void fram_mqtt_password_retrieve() +void eeprom_mqtt_password_retrieve() { - ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32); + ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32); } -/** - * @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(FRAM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20); + ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20); } -/** - * @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(FRAM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20); + ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20); } - -void fram_mqtt_useauth_retrieve() +void eeprom_mqtt_useauth_retrieve() { - MQTT_USE_AUTH = ESPMega_FRAM.read8(FRAM_ADDRESS_MQTT_USEAUTH); + MQTT_USE_AUTH = ESPMega_FRAM.read8(EEPROM_ADDRESS_MQTT_USEAUTH); } -/** - * @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(FRAM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH); + ESPMega_FRAM.write8(EEPROM_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. - * - * This function resets the device to its factory default settings by formatting the FRAM, - * setting default IP address, gateway, and netmask values, and restarting the device. - * - */ void factory_reset() { for (int i = 5; i > 0; i--) @@ -1920,11 +1317,6 @@ 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(); @@ -1933,13 +1325,6 @@ void factory_reset() #endif ESP.restart(); } - -/** - * @brief Checks if the device should perform a factory reset on boot. - * - * This function checks if pin 2 is pulled low on boot. If it is, the device will perform a factory reset. - * - */ void check_boot_reset() { pinMode(2, INPUT_PULLUP); @@ -1947,359 +1332,4 @@ 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 fb6afc7..bf03bf5 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -1,12 +1,3 @@ -/** - * @brief Header file for the ESPMega IoT Core library. - * - * This library provides functions for controlling various IoT modules such as climate, IR, and input/output. - * It also includes functions for MQTT communication, LCD display, and OTA updates. - * - * @note This library requires the ESPMegaPRO library to be installed. - * - */ #pragma once #include @@ -18,6 +9,7 @@ #endif #include #include +#include #include #include #ifdef ENABLE_IR_MODULE @@ -33,7 +25,7 @@ #include #include #endif -#include "espmega_iot_lcd.hpp" +#include "lcd.hpp" #ifdef ENABLE_CLIMATE_MODULE #include "ir_codes.hpp" @@ -43,17 +35,15 @@ #endif #include "espmega_iot_timer.hpp" -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(); -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 pwm_state_callback(String topic, String message); +void pwm_value_callback(String topic, String message); +void state_request_callback(String topic, String message); void io_begin(); void ir_loop(); @@ -61,9 +51,8 @@ void ota_begin(); void publish_pwm_states(); void publish_pwm_state(int id); -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_set_state(int id, int state); +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); @@ -77,7 +66,7 @@ void publish_env_state(); uint8_t ac_get_temperature(); uint8_t ac_get_mode(); uint8_t ac_get_fan_speed(); -void ac_state_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length); +void ac_state_callback(String topic, String message); void ac_set_state(int mode, int temperature, int fan_speed); void publish_input_states(); @@ -106,8 +95,8 @@ void trigger13(); void trigger14(); void trigger15(); -void fram_retrieve_init(); -void fram_pwm_update(); +void eeprom_retrieve_init(); +void eeprom_pwm_update(); void lcd_ac_refresh_fan(); void lcd_ac_refresh_mode(); @@ -117,47 +106,20 @@ void set_netmask(String address); void set_dns(String address); void set_gw(String address); void set_mqtt_server(String 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 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 set_hostname(String hostname); -void fram_hostname_retrieve(); +void eeprom_hostname_retrieve(); void set_basetopic(String topic); -void fram_basetopic_retrieve(); +void eeprom_basetopic_retrieve(); void mqtt_port_set(uint16_t port); -void fram_mqtt_port_retrieve(); -void fram_mqtt_username_retrieve(); -void fram_mqtt_password_retrieve(); +void eeprom_mqtt_port_retrieve(); +void eeprom_mqtt_username_retrieve(); +void eeprom_mqtt_password_retrieve(); void set_mqtt_username(String username); void set_mqtt_password(String password); -void fram_mqtt_useauth_retrieve(); +void eeprom_mqtt_useauth_retrieve(); void set_mqtt_useauth(bool use_auth); void factory_reset(); -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 +void check_boot_reset(); \ No newline at end of file diff --git a/src/espmega_iot_emon.cpp b/src/espmega_iot_emon.cpp index d47aa92..863de9f 100644 --- a/src/espmega_iot_emon.cpp +++ b/src/espmega_iot_emon.cpp @@ -1,14 +1,5 @@ - - #include "espmega_iot_emon.hpp" -/** - * @brief Constructor for ESPMega_CT class. - * - * @param analog_pin The analog pin to read the current sensor from. - * @param adc_to_watts A function pointer to a function that converts ADC value to watts. - * @param fram_address The address of the FRAM to store energy data. - */ ESPMega_CT::ESPMega_CT(uint8_t analog_pin, float (*adc_to_watts)(uint16_t adc_value), uint32_t fram_address) { this->analog_pin = analog_pin; @@ -16,11 +7,6 @@ ESPMega_CT::ESPMega_CT(uint8_t analog_pin, float (*adc_to_watts)(uint16_t adc_va this->adc_to_watts = adc_to_watts; } -/** - * @brief Initializes the ESPMega_CT object. - * - * Reads the energy data from FRAM, sets the last conversion timestamp to current time, and calculates the current power. - */ void ESPMega_CT::begin() { this->last_conversion_timestamp = millis(); @@ -28,11 +14,6 @@ void ESPMega_CT::begin() this->power = adc_to_watts(ESPMega_analogRead(this->analog_pin)); } -/** - * @brief The main loop function of the ESPMega_CT object. - * - * Calculates the energy consumed since the last loop iteration, updates the current power, and writes the energy data to FRAM. - */ void ESPMega_CT::loop() { this->energy += (millis() - this->last_conversion_timestamp) / 3600000 * this->power; @@ -41,41 +22,22 @@ void ESPMega_CT::loop() ESPMega_FRAM.write(fram_address, (uint8_t *)&this->energy, 16); } -/** - * @brief Resets the energy data stored in FRAM and the energy variable. - */ void ESPMega_CT::reset_energy() { this->energy = 0; ESPMega_FRAM.write16(fram_address, 0); } -/** - * @brief Returns the energy consumed since the object was initialized. - * - * @return The energy consumed since the object was initialized. - */ long double ESPMega_CT::get_energy() { return this->energy; } -/** - * @brief Returns the current power consumption. - * - * @return The current power consumption. - */ float ESPMega_CT::get_power() { return this->power; } -/** - * @brief A built-in function to convert ADC value to watts. - * - * @param adc_value The ADC value to convert to watts. - * @return The power in watts. - */ float ESPMega_CT::adc_to_watts_builtin(uint16_t adc_value) { const float RATIO = 0.1; diff --git a/src/espmega_iot_emon.hpp b/src/espmega_iot_emon.hpp index 8387b58..818ce36 100644 --- a/src/espmega_iot_emon.hpp +++ b/src/espmega_iot_emon.hpp @@ -1,54 +1,13 @@ -/** - * @brief Class for measuring current and power consumption using a current transformer and an ADC. - * - */ #pragma once - #include - class ESPMega_CT { public: - /** - * @brief Construct a new ESPMega_CT object - * - * @param analog_pin The analog pin to which the current transformer is connected. - * @param adc_to_watts A function pointer to a function that converts ADC values to watts. - * @param fram_address The address in FRAM where the energy consumption data is stored. - */ ESPMega_CT(uint8_t analog_pin,float(*adc_to_watts)(uint16_t adc_value), uint32_t fram_address); - - /** - * @brief Initializes the object. - * - */ void begin(); - - /** - * @brief Updates the power and energy consumption values. - * - */ void loop(); - - /** - * @brief Returns the current power consumption in watts. - * - * @return float The current power consumption in watts. - */ float get_power(); - - /** - * @brief Returns the total energy consumption in watt-hours. - * - * @return long double The total energy consumption in watt-hours. - */ long double get_energy(); - - /** - * @brief Resets the energy consumption value to zero. - * - */ void reset_energy(); - private: uint8_t analog_pin; uint32_t fram_address; diff --git a/src/espmega_iot_homeassistant.cpp.disabled b/src/espmega_iot_homeassistant.cpp.disabled deleted file mode 100644 index 0a95e53..0000000 --- a/src/espmega_iot_homeassistant.cpp.disabled +++ /dev/null @@ -1,28 +0,0 @@ -#include "espmega_iot_homeassistant.hpp" - -void publishDiscoveryPayload(const char* component, const char* config) { - String topic = "homeassistant/" + String(component) + "/config"; - mqttClient.publish(topic.c_str(), config); -} -void publishDiscoveryPayload(const char* component, const char* name, const char* deviceClass, const char* unitOfMeasurement, const char* stateTopic, const char* commandTopic, const char* availabilityTopic, const char* payloadAvailable, const char* payloadNotAvailable, const char* uniqueId) { - String config = "{"; - config += "\"name\":\"" + String(name) + "\","; - config += "\"device_class\":\"" + String(deviceClass) + "\","; - config += "\"unit_of_measurement\":\"" + String(unitOfMeasurement) + "\","; - config += "\"state_topic\":\"" + String(stateTopic) + "\","; - config += "\"command_topic\":\"" + String(commandTopic) + "\","; - config += "\"availability_topic\":\"" + String(availabilityTopic) + "\","; - config += "\"payload_available\":\"" + String(payloadAvailable) + "\","; - config += "\"payload_not_available\":\"" + String(payloadNotAvailable) + "\","; - config += "\"unique_id\":\"" + String(uniqueId) + "\""; - config += "}"; - - String topic = "homeassistant/" + String(component) + "/config"; - mqttClient.publish(topic.c_str(), config.c_str()); -} - -// Example usage: -publishDiscoveryPayload("sensor", "temperature", "temperature", "°C", "home/temperature", "home/temperature/set", "home/availability", "online", "offline", "temperature_sensor"); -publishDiscoveryPayload("binary_sensor", "motion", "motion", "", "home/motion", "home/motion/set", "home/availability", "online", "offline", "motion_sensor"); -publishDiscoveryPayload("climate", "thermostat", "temperature", "°C", "home/thermostat", "home/thermostat/set", "home/availability", "online", "offline", "thermostat"); -publishDiscoveryPayload("switch", "light", "switch", "", "home/light", "home/light/set", "home/availability", "online", "offline", "light_switch"); diff --git a/src/espmega_iot_homeassistant.hpp.disabled b/src/espmega_iot_homeassistant.hpp.disabled deleted file mode 100644 index 2faf487..0000000 --- a/src/espmega_iot_homeassistant.hpp.disabled +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include \ No newline at end of file diff --git a/src/espmega_iot_lcd.cpp b/src/espmega_iot_lcd.cpp deleted file mode 100644 index 1f03338..0000000 --- a/src/espmega_iot_lcd.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include - -/** - * @brief Sends stop bit to LCD. - * - * This function sends a stop bit to the LCD. It is only enabled if the ENABLE_INTERNAL_LCD macro is defined. - */ -void lcd_send_stop_bit() -{ -#ifdef ENABLE_INTERNAL_LCD - Serial.write(0xFF); - Serial.write(0xFF); - Serial.write(0xFF); -#endif -} - -/** - * Sends a command to the LCD display. - * - * @param command The command to send to the LCD display. - */ -void lcd_send_command(String command) -{ -#ifdef ENABLE_INTERNAL_LCD - lcd_send_stop_bit(); - Serial.print(command); - lcd_send_stop_bit(); -#endif -} - -/** - * @brief Resets the LCD display. - * - * If ENABLE_INTERNAL_LCD is defined, sends a reset command to the LCD display. - * - */ -void lcd_reset() -{ -#ifdef ENABLE_INTERNAL_LCD - lcd_send_stop_bit(); - lcd_send_command("rest"); - lcd_send_stop_bit(); -#endif -} - -/** - * Initializes the LCD display. - */ -void lcd_init() -{ -#ifdef ENABLE_INTERNAL_LCD - lcd_reset(); - delay(750); -#endif -} - -/** - * @brief Starts the upload process to the LCD. - * - * @param size The size of the data to be uploaded. - * @return true if the upload process started successfully, false otherwise. - */ -bool lcd_upload_start(size_t size) -{ - Serial.begin(115200); - lcd_send_stop_bit(); - Serial.print("rest"); - lcd_send_stop_bit(); - Serial.print("connect"); - lcd_send_stop_bit(); - delay(1000); - Serial.print("whmi-wri 1024,115200,res0"); - lcd_send_stop_bit(); - lcd_wait_ack(); -} - -/** - * Writes data to the LCD upload buffer. - * - * @param data Pointer to the data to be written. - * @param size Size of the data to be written. - * @return True if the write was successful, false otherwise. - */ -bool lcd_upload_write(uint8_t *data, size_t size) -{ - for (int i = 0; i < size; i++) - { - Serial.write(data[i]); - } -} - -/** - * Waits for an acknowledgement signal from the LCD. - * @return true if acknowledgement signal is received, false otherwise. - */ -bool lcd_wait_ack() -{ - bool data_ok = false; - for (int i; i < 50; i++) - { - if (Serial.read() == 0x05) - { - data_ok = true; - break; - } - delay(100); - } - return data_ok; -} \ No newline at end of file diff --git a/src/espmega_iot_lcd.hpp b/src/espmega_iot_lcd.hpp deleted file mode 100644 index 0e70e3c..0000000 --- a/src/espmega_iot_lcd.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - - -void lcd_send_stop_bit(); -void lcd_send_command(String command); -String lcd_wait_response(); -void lcd_reset(); -void lcd_init(); - -bool lcd_upload_start(size_t size); -bool lcd_upload_write(uint8_t* data, size_t size); -bool lcd_wait_ack(); \ No newline at end of file diff --git a/src/espmega_iot_timer.cpp b/src/espmega_iot_timer.cpp index 6781e7c..eb25edd 100644 --- a/src/espmega_iot_timer.cpp +++ b/src/espmega_iot_timer.cpp @@ -1,9 +1,5 @@ #include "espmega_iot_timer.hpp" -/** - * @brief Loop function that checks if the timer should run and calls the timer callback function. - * - */ void ESPMega_Timer::loop() { rtctime_t curtime = ESPMega_getTime(); if(today!=curtime.day) { @@ -18,14 +14,6 @@ void ESPMega_Timer::loop() { } } -/** - * @brief Constructor for ESPMega_Timer class. - * - * @param hour The hour at which the timer should run. - * @param minute The minute at which the timer should run. - * @param timer_callback The function to be called when the timer runs. - * @param fram_address The address in FRAM where the timer state is stored. - */ ESPMega_Timer::ESPMega_Timer(uint8_t hour,uint8_t minute,void(*timer_callback)(), uint32_t fram_address) { this->hr = hour; this->min = minute; @@ -33,10 +21,6 @@ ESPMega_Timer::ESPMega_Timer(uint8_t hour,uint8_t minute,void(*timer_callback)() this->fram_address = fram_address; } -/** - * @brief Begins the timer and sets the initial timer state. - * - */ void ESPMega_Timer::begin() { rtctime_t curtime = ESPMega_getTime(); this-> today = curtime.day; @@ -44,12 +28,6 @@ void ESPMega_Timer::begin() { loop(); } -/** - * @brief Sets the hour and minute at which the timer should run. - * - * @param hour The hour at which the timer should run. - * @param minute The minute at which the timer should run. - */ void ESPMega_Timer::set(uint8_t hour,uint8_t minute) { rtctime_t curtime = ESPMega_getTime(); if ((hr < curtime.hours || (hr == curtime.hours && min <= curtime.minutes))) { diff --git a/src/espmega_iot_timer.hpp b/src/espmega_iot_timer.hpp index 5d7d54d..395c6e8 100644 --- a/src/espmega_iot_timer.hpp +++ b/src/espmega_iot_timer.hpp @@ -1,43 +1,12 @@ #pragma once - #include -/** - * @brief Class representing a timer for ESPMega board. - * - */ class ESPMega_Timer { public: - /** - * @brief Loop function to be called in the main loop. - * - */ void loop(); - - /** - * @brief Constructor for ESPMega_Timer class. - * - * @param hour The hour at which the timer should trigger. - * @param minute The minute at which the timer should trigger. - * @param timer_callback The function to be called when the timer triggers. - * @param fram_address The address of the FRAM memory to store the timer state. - */ - ESPMega_Timer(uint8_t hour, uint8_t minute, void(*timer_callback)(), uint32_t fram_address); - - /** - * @brief Set the hour and minute at which the timer should trigger. - * - * @param hour The hour at which the timer should trigger. - * @param minute The minute at which the timer should trigger. - */ - void set(uint8_t hour, uint8_t minute); - - /** - * @brief Begin the timer. - * - */ + ESPMega_Timer(uint8_t hour,uint8_t minute,void(*timer_callback)(), uint32_t fram_address); + void set(uint8_t hour,uint8_t minute); void begin(); - private: uint8_t today; uint8_t timer_ran_today; diff --git a/src/lcd.cpp b/src/lcd.cpp new file mode 100644 index 0000000..bf089c5 --- /dev/null +++ b/src/lcd.cpp @@ -0,0 +1,37 @@ +#include +#include + +void lcd_send_stop_bit() +{ +#ifdef ENABLE_INTERNAL_LCD + Serial.write(0xFF); + Serial.write(0xFF); + Serial.write(0xFF); +#endif +} + +void lcd_send_command(String command) +{ +#ifdef ENABLE_INTERNAL_LCD + lcd_send_stop_bit(); + Serial.print(command); + lcd_send_stop_bit(); +#endif +} + +void lcd_reset() +{ +#ifdef ENABLE_INTERNAL_LCD + lcd_send_stop_bit(); + lcd_send_command("rest"); + lcd_send_stop_bit(); +#endif +} + +void lcd_init() +{ +#ifdef ENABLE_INTERNAL_LCD + lcd_reset(); + delay(750); +#endif +} \ No newline at end of file diff --git a/src/lcd.hpp b/src/lcd.hpp new file mode 100644 index 0000000..321410c --- /dev/null +++ b/src/lcd.hpp @@ -0,0 +1,11 @@ +#ifndef EMG_LCD_ENABLED +#include + +#define EMG_LCD_ENABLED + +void lcd_send_stop_bit(); +void lcd_send_command(String command); +String lcd_wait_response(); +void lcd_reset(); +void lcd_init(); +#endif \ No newline at end of file diff --git a/src/user_code.cpp b/src/user_code.cpp index 49d4be7..50f916a 100644 --- a/src/user_code.cpp +++ b/src/user_code.cpp @@ -1,29 +1,12 @@ #include -//Timer Components -ESPMega_Timer timer1(0, 50, timer1_callback, 15001); - -// Display Componets -// Link with Dual state button object with id 2 on page 1 named bt0 -NexDSButton bt0 = NexDSButton(1, 2, "bt0"); -// List of Component ID Message to listen to -NexTouch *nex_listen_list[] = - { - &bt0, - NULL}; - -void bt0PopCallback(void *ptr) -{ - pwm_toggle(2); -} - /* This Code will run right after ESPMega PRO's Peripheral Initialization Routine */ void user_pre_init() { - nexInit(); + } /* @@ -31,12 +14,7 @@ This code will run after every component is initialized */ void user_init() { - timer1.begin(); - ESPMega_EXTLCD.print("page home"); - ESPMega_EXTLCD.write(0xFF); - ESPMega_EXTLCD.write(0xFF); - ESPMega_EXTLCD.write(0xFF); - bt0.attachPop(bt0PopCallback, &bt0); + } /* @@ -44,7 +22,7 @@ This code will run once every event loop */ void user_loop() { - nexLoop(nex_listen_list); + } /* @@ -56,11 +34,7 @@ void virtual_interrupt_user_callback(int pin, int state) void pwm_changed_user_callback(int pin) { - if (pin == 2) - { - // inform the lcd when pwm 2 changed - bt0.setValue(pwm_get_state(2)); - } + } /* @@ -68,18 +42,12 @@ This code will run every 15 seconds */ void timer_tick_callback() { - if (standalone) - { - timer1.loop(); - } + } void timer1_callback() { - for (int i = 0; i < 16; i++) - { - pwm_set_state(i, 1); - } + } void ac_changed_user_callback(int mode, int temperature, int fan_speed) { @@ -92,8 +60,4 @@ void mqtt_connected_user_callback() { void user_state_request_callback() { -} - -void user_mqtt_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 8b3e361..4c74cd7 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -1,64 +1,44 @@ #pragma once #include -#include #include #include #include "espmega_iot_timer.hpp" #include "espmega_iot_external_lcd.hpp" -// Bus Overclocking Configuration -// Do not enable if you are using external I/O cards as it will cause signal integrity issues. -// Choose only one mode -//#define OVERCLOCK_FM -//#define OVERCLOCK_FM2 - -// I/O Configuration -#define VIRTUAL_INTERRUPT_PRELOAD // Preload Virtual Interrupts buffer - // 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 +#define ENABLE_INTERNAL_LCD +#define ENABLE_IR_MODULE +#define ENABLE_CLIMATE_MODULE // Require IR Module +#define ENABLE_WEBUI -// IR Kit Configuration +// Infrared Transciever #define IR_RECIEVE_PIN 35 -#define IR_SEND_PIN 5 +#define IR_SEND_PIN 17 #define MARK_EXCESS_MICROS 20 -#define IR_RAW_BUFFER_LENGTH 750 +#define 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 -#define TXD2 4 -#define RXD2 17 +//#define ENABLE_EXTERNAL_LCD +//#define TXD2 4 +//#define RXD2 17 #ifdef ENABLE_EXTERNAL_LCD #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 virtual_interrupt_user_callback(int pin, int state); +void mqtt_connected_user_callback(); +void user_state_request_callback(); + // ESPMega IoT Core Build-in Functions extern void pwm_set_state(int id, int state); @@ -70,26 +50,10 @@ 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(); -#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 +extern bool standalone; +extern PubSubClient mqtt_client; +extern PubSubClientTools mqtt; \ No newline at end of file