From 0bb47ef12848d2e5d821381464d7a3a1489a72d9 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Tue, 14 Nov 2023 17:39:36 +0700 Subject: [PATCH 01/25] publish env during state request --- src/espmega_iot_core.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 0ff5efc..b900bb9 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -758,6 +758,7 @@ void state_request_callback() publish_pwm_states(); #ifdef ENABLE_CLIMATE_MODULE publish_ac_state(); + publish_env_state(); #endif user_state_request_callback(); } From b102b25f17962c8f60c220b2c948d3bcd125baee Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Wed, 15 Nov 2023 16:55:43 +0700 Subject: [PATCH 02/25] robot code --- src/espmega_iot_core.cpp | 382 ++++++++++++++++++++- src/espmega_iot_core.hpp | 9 + src/espmega_iot_emon.cpp | 38 ++ src/espmega_iot_emon.hpp | 41 +++ src/espmega_iot_homeassistant.cpp.disabled | 28 ++ src/espmega_iot_homeassistant.hpp.disabled | 2 + src/espmega_iot_lcd.cpp | 37 ++ src/espmega_iot_timer.cpp | 22 ++ src/espmega_iot_timer.hpp | 33 ++ 9 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 src/espmega_iot_homeassistant.cpp.disabled create mode 100644 src/espmega_iot_homeassistant.hpp.disabled diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index b900bb9..5246e17 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -1,3 +1,15 @@ +/** + * @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 @@ -190,6 +202,10 @@ void loop() #endif } +/** + * @brief Retrieves data from EEPROM and initializes various variables and topics. + * + */ void eeprom_retrieve_init() { // EEPROM Data Retrival @@ -278,6 +294,16 @@ void eeprom_retrieve_init() } #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, []() @@ -427,6 +453,7 @@ void ota_begin() } #endif + void io_begin() { Serial.println("Initializing I/O . . ."); @@ -436,6 +463,14 @@ 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 "); @@ -462,6 +497,17 @@ 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()) @@ -500,6 +546,10 @@ 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++) @@ -519,6 +569,13 @@ void mqtt_subscribe() mqtt.subscribe(STATE_REQUEST_TOPIC); } +/** + * @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. + */ void mqtt_callback(char *topic, byte *payload, unsigned int length) { uint8_t topic_length = strlen(topic); @@ -544,6 +601,10 @@ void mqtt_callback(char *topic, byte *payload, unsigned int length) user_mqtt_callback(topic, topic_length, payload_nt, length); } +/** + * @brief Initializes the threads for various tasks such as MQTT connection, environment reporting, EEPROM PWM update, and user timer tick. + * + */ void thread_initialization() { Serial.println("Initializing Threads . . ."); @@ -560,6 +621,14 @@ void thread_initialization() user_timer_tick.setInterval(15000); } +/** + * @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. + */ void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) { int a = topic[5] - '0'; @@ -575,6 +644,17 @@ void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsign } } +/** + * @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. + */ void pwm_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) { int a = topic[5] - '0'; @@ -584,6 +664,15 @@ void pwm_value_callback(char *topic, uint8_t topic_length, char *payload, unsign 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) { @@ -616,6 +705,10 @@ 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++) @@ -624,6 +717,11 @@ void publish_pwm_states() } } +/** + * @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) { int state = pwm_states[id]; @@ -645,6 +743,12 @@ void publish_pwm_state(int id) 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. + */ void pwm_set_state(int id, int state) { if (state != pwm_states[id]) @@ -663,6 +767,12 @@ 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. + */ void pwm_set_value(int id, int value) { pwm_values[id] = value; @@ -678,12 +788,22 @@ void pwm_set_value(int id, int value) 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); @@ -699,6 +819,13 @@ 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]; @@ -707,6 +834,11 @@ 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]; @@ -732,6 +864,10 @@ 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++) @@ -739,12 +875,24 @@ 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'; @@ -752,6 +900,12 @@ void publish_input_state(int id, int state) mqtt.publish(INPUTS_TOPIC, state ? "1" : "0"); } +/** + * @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() { publish_input_states(); @@ -774,6 +928,10 @@ void ir_loop() #endif #ifdef ENABLE_CLIMATE_MODULE +/** + * @brief Publishes the current state of the air conditioner to MQTT topics. + * + */ void publish_ac_state() { switch (ac_mode) @@ -809,6 +967,17 @@ void publish_ac_state() } } +/** + * @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) { if (!strcmp(topic, AC_SET_TEMPERATURE_TOPIC)) @@ -855,6 +1024,13 @@ void ac_state_callback(char *topic, uint8_t topic_length, char *payload, unsigne } } +/** + * @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; @@ -894,6 +1070,14 @@ 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() { int errorCode = env_sensor.read(); @@ -929,6 +1113,10 @@ void publish_env_state() #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); @@ -938,6 +1126,10 @@ void lcd_begin() lcd_refresh(); } +/** + * @brief Runs the LCD loop, updating the display and listening for input. + * + */ void lcd_loop() { lcd_thread_controller.run(); @@ -950,6 +1142,10 @@ void lcd_loop() } } +/** + * @brief Refreshes the LCD display if the current page is 1. + * + */ void lcd_refresh_pd() { if (lcd_current_page == 1) @@ -958,6 +1154,14 @@ 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) @@ -1020,6 +1224,15 @@ 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]; @@ -1029,7 +1242,18 @@ 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 @@ -1038,6 +1262,13 @@ 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); @@ -1171,52 +1402,101 @@ void trigger15() } #endif // End Internal LCD Code Block +/** + * @brief Updates the PWM states and values in EEPROM if they have changed. + * + * If the current PWM states or values are different from the ones stored in EEPROM, + * this function updates the EEPROM with the current values. + */ void eeprom_pwm_update() { if (memcmp(pwm_states, pwm_states_eeprom, 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_eeprom, 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 EEPROM. + * + * @param address The IP address to set. + */ void set_ip(String address) { IP.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]); } + +/** + * @brief Sets the subnet mask for the device. + * + * @param address The subnet mask address to set. + */ void set_netmask(String address) { SUBNET.fromString(address); 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); eeprom_ip_update(EEPROM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]); } + +/** + * @brief Sets the gateway IP address and updates the EEPROM. + * + * @param address The gateway IP address as a String. + */ void set_gw(String address) { GATEWAY.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]); } + +/** + * @brief Sets the MQTT server address and updates the EEPROM. + * + * @param address The MQTT server address as a String. + */ void set_mqtt_server(String address) { MQTT_SERVER.fromString(address); eeprom_ip_update(EEPROM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]); } + +/** + * @brief Updates the IP address in EEPROM 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 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 EEPROM memory. + * + * @param rom_address The address in EEPROM memory where the IP address is stored. + * @return The retrieved IP address. + */ IPAddress eeprom_ip_retrieve(uint16_t rom_address) { uint8_t addressblock[4]; @@ -1224,34 +1504,61 @@ IPAddress eeprom_ip_retrieve(uint16_t rom_address) 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(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } +/** + * @brief Retrieves the hostname from EEPROM and stores it in the HOSTNAME variable. + * + */ void eeprom_hostname_retrieve() { ESPMega_FRAM.read(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } +/** + * @brief Sets the base topic for MQTT communication and writes it to EEPROM. + * + * @param topic The base topic to set. + */ void set_basetopic(String topic) { topic.toCharArray(MQTT_BASE_TOPIC, 20); ESPMega_FRAM.write(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } +/** + * @brief Retrieves the MQTT base topic from EEPROM and stores it in MQTT_BASE_TOPIC array. + * + */ void eeprom_basetopic_retrieve() { ESPMega_FRAM.read(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } +/** + * @brief Sets the MQTT port in the EEPROM. + * + * @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(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); } +/** + * @brief Retrieves the MQTT port from EEPROM and stores it in the MQTT_PORT variable. + * + */ void eeprom_mqtt_port_retrieve() { uint8_t port_arr[2]; @@ -1259,64 +1566,128 @@ void eeprom_mqtt_port_retrieve() 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 EEPROM and stores it in the MQTT_USERNAME global variable. + * + */ void eeprom_mqtt_username_retrieve() { ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32); } +/** + * @brief Retrieves the MQTT password from EEPROM and stores it in the MQTT_PASSWORD global variable. + * + */ void eeprom_mqtt_password_retrieve() { ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32); } +/** + * @brief Sets the MQTT username and writes it to the EEPROM. + * + * @param username The MQTT username to set. + */ void set_mqtt_username(String username) { username.toCharArray(MQTT_USERNAME, 32); ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20); } +/** + * @brief Sets the MQTT password and writes it to the EEPROM. + * + * @param password The MQTT password to set. + */ void set_mqtt_password(String password) { password.toCharArray(MQTT_PASSWORD, 32); ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20); } + void eeprom_mqtt_useauth_retrieve() { MQTT_USE_AUTH = ESPMega_FRAM.read8(EEPROM_ADDRESS_MQTT_USEAUTH); } +/** + * @brief Sets the MQTT_USE_AUTH flag and writes it to the EEPROM. + * + * @param use_auth A boolean value indicating whether to use authentication for MQTT. + */ void set_mqtt_useauth(bool use_auth) { MQTT_USE_AUTH = use_auth; ESPMega_FRAM.write8(EEPROM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH); } +/** + * @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--) @@ -1353,6 +1724,13 @@ 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); diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp index 959a19c..f542632 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -1,3 +1,12 @@ +/** + * @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 diff --git a/src/espmega_iot_emon.cpp b/src/espmega_iot_emon.cpp index 863de9f..d47aa92 100644 --- a/src/espmega_iot_emon.cpp +++ b/src/espmega_iot_emon.cpp @@ -1,5 +1,14 @@ + + #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; @@ -7,6 +16,11 @@ 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(); @@ -14,6 +28,11 @@ 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; @@ -22,22 +41,41 @@ 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 818ce36..8387b58 100644 --- a/src/espmega_iot_emon.hpp +++ b/src/espmega_iot_emon.hpp @@ -1,13 +1,54 @@ +/** + * @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 new file mode 100644 index 0000000..0a95e53 --- /dev/null +++ b/src/espmega_iot_homeassistant.cpp.disabled @@ -0,0 +1,28 @@ +#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 new file mode 100644 index 0000000..2faf487 --- /dev/null +++ b/src/espmega_iot_homeassistant.hpp.disabled @@ -0,0 +1,2 @@ +#pragma once +#include \ No newline at end of file diff --git a/src/espmega_iot_lcd.cpp b/src/espmega_iot_lcd.cpp index d4c89b9..1f03338 100644 --- a/src/espmega_iot_lcd.cpp +++ b/src/espmega_iot_lcd.cpp @@ -1,6 +1,11 @@ #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 @@ -10,6 +15,11 @@ void lcd_send_stop_bit() #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 @@ -19,6 +29,12 @@ void lcd_send_command(String command) #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 @@ -28,6 +44,9 @@ void lcd_reset() #endif } +/** + * Initializes the LCD display. + */ void lcd_init() { #ifdef ENABLE_INTERNAL_LCD @@ -36,6 +55,12 @@ void lcd_init() #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); @@ -49,6 +74,14 @@ bool lcd_upload_start(size_t size) 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++) @@ -57,6 +90,10 @@ bool lcd_upload_write(uint8_t *data, size_t size) } } +/** + * 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; diff --git a/src/espmega_iot_timer.cpp b/src/espmega_iot_timer.cpp index eb25edd..6781e7c 100644 --- a/src/espmega_iot_timer.cpp +++ b/src/espmega_iot_timer.cpp @@ -1,5 +1,9 @@ #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) { @@ -14,6 +18,14 @@ 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; @@ -21,6 +33,10 @@ 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; @@ -28,6 +44,12 @@ 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 395c6e8..eb5778d 100644 --- a/src/espmega_iot_timer.hpp +++ b/src/espmega_iot_timer.hpp @@ -1,12 +1,45 @@ #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(); ESPMega_Timer(uint8_t hour,uint8_t minute,void(*timer_callback)(), uint32_t fram_address); void set(uint8_t hour,uint8_t minute); + + /** + * @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. + * + */ void begin(); + private: uint8_t today; uint8_t timer_ran_today; From 2c2427ee3c76317d524907632b7bd882479f966b Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Wed, 15 Nov 2023 23:57:02 +0700 Subject: [PATCH 03/25] Update espmega_iot_timer.hpp --- src/espmega_iot_timer.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/espmega_iot_timer.hpp b/src/espmega_iot_timer.hpp index eb5778d..5d7d54d 100644 --- a/src/espmega_iot_timer.hpp +++ b/src/espmega_iot_timer.hpp @@ -13,8 +13,6 @@ class ESPMega_Timer { * */ void loop(); - ESPMega_Timer(uint8_t hour,uint8_t minute,void(*timer_callback)(), uint32_t fram_address); - void set(uint8_t hour,uint8_t minute); /** * @brief Constructor for ESPMega_Timer class. From e124c73f670fdb2f9eef71c6a538fa9a3bbd23b3 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 16 Nov 2023 14:51:17 +0700 Subject: [PATCH 04/25] fix failing build without climate module --- src/espmega_iot_core.cpp | 165 ++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 81 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 5246e17..e797661 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -1,11 +1,11 @@ /** * @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 + * + * 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 */ @@ -204,7 +204,7 @@ void loop() /** * @brief Retrieves data from EEPROM and initializes various variables and topics. - * + * */ void eeprom_retrieve_init() { @@ -296,12 +296,12 @@ void eeprom_retrieve_init() #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() @@ -453,7 +453,6 @@ void ota_begin() } #endif - void io_begin() { Serial.println("Initializing I/O . . ."); @@ -465,10 +464,10 @@ void io_begin() /** * @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. - * + * + * @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() @@ -499,13 +498,13 @@ void network_begin() /** * @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() @@ -548,7 +547,7 @@ void mqtt_connect() /** * @brief Subscribes to MQTT topics for controlling PWM, climate module and requesting device state. - * + * */ void mqtt_subscribe() { @@ -571,7 +570,7 @@ void mqtt_subscribe() /** * @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. @@ -591,19 +590,23 @@ void mqtt_callback(char *topic, byte *payload, unsigned int 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,STATE_REQUEST_TOPIC)) { + } + 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, EEPROM PWM update, and user timer tick. - * + * */ void thread_initialization() { @@ -623,7 +626,7 @@ void thread_initialization() /** * @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. @@ -646,10 +649,10 @@ void pwm_state_callback(char *topic, uint8_t topic_length, char *payload, unsign /** * @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. @@ -666,10 +669,10 @@ void pwm_value_callback(char *topic, uint8_t topic_length, char *payload, unsign /** * @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). */ @@ -707,7 +710,7 @@ void virtual_interrupt_loop() /** * @brief Publishes the current state of all PWM channels. - * + * */ void publish_pwm_states() { @@ -719,7 +722,7 @@ void publish_pwm_states() /** * @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) @@ -745,7 +748,7 @@ void publish_pwm_state(int id) /** * @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. */ @@ -769,7 +772,7 @@ 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. */ @@ -790,7 +793,7 @@ void pwm_set_value(int id, int value) /** * @brief Toggles the state of a PWM pin. - * + * * @param id The ID of the PWM pin to toggle. */ void pwm_toggle(int id) @@ -821,7 +824,7 @@ 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. @@ -836,7 +839,7 @@ boolean pwm_group_state(int id1, int id2) /** * @brief Cycles the PWM value for the given id. - * + * * @param id The id of the PWM pin. */ void pwm_cycle_value(int id) @@ -866,7 +869,7 @@ void pwm_cycle_value(int id) /** * @brief Publishes the input states for all virtual input pins. - * + * */ void publish_input_states() { @@ -878,7 +881,7 @@ void publish_input_states() /** * @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) @@ -889,7 +892,7 @@ void publish_input_state(int id) /** * @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). */ @@ -902,7 +905,7 @@ void publish_input_state(int id, int state) /** * @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. */ @@ -930,7 +933,7 @@ void ir_loop() #ifdef ENABLE_CLIMATE_MODULE /** * @brief Publishes the current state of the air conditioner to MQTT topics. - * + * */ void publish_ac_state() { @@ -969,10 +972,10 @@ void publish_ac_state() /** * @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. @@ -1026,7 +1029,7 @@ void ac_state_callback(char *topic, uint8_t topic_length, char *payload, unsigne /** * @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). @@ -1072,10 +1075,10 @@ void ac_set_state(int mode, int temperature, int 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() @@ -1115,7 +1118,7 @@ void publish_env_state() #ifdef ENABLE_INTERNAL_LCD /** * @brief Initializes the LCD display and sets up the refresh intervals for the top bar and page. - * + * */ void lcd_begin() { @@ -1128,7 +1131,7 @@ void lcd_begin() /** * @brief Runs the LCD loop, updating the display and listening for input. - * + * */ void lcd_loop() { @@ -1144,7 +1147,7 @@ void lcd_loop() /** * @brief Refreshes the LCD display if the current page is 1. - * + * */ void lcd_refresh_pd() { @@ -1156,11 +1159,11 @@ 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() { @@ -1227,10 +1230,10 @@ void lcd_refresh() /** * @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() @@ -1246,12 +1249,12 @@ void lcd_top_bar_update() #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() @@ -1264,10 +1267,10 @@ void lcd_ac_refresh_mode() /** * @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() { @@ -1404,7 +1407,7 @@ void trigger15() /** * @brief Updates the PWM states and values in EEPROM if they have changed. - * + * * If the current PWM states or values are different from the ones stored in EEPROM, * this function updates the EEPROM with the current values. */ @@ -1424,7 +1427,7 @@ void eeprom_pwm_update() /** * @brief Sets the IP address and updates it in EEPROM. - * + * * @param address The IP address to set. */ void set_ip(String address) @@ -1435,7 +1438,7 @@ void set_ip(String address) /** * @brief Sets the subnet mask for the device. - * + * * @param address The subnet mask address to set. */ void set_netmask(String address) @@ -1456,7 +1459,7 @@ void set_dns(String address) /** * @brief Sets the gateway IP address and updates the EEPROM. - * + * * @param address The gateway IP address as a String. */ void set_gw(String address) @@ -1467,7 +1470,7 @@ void set_gw(String address) /** * @brief Sets the MQTT server address and updates the EEPROM. - * + * * @param address The MQTT server address as a String. */ void set_mqtt_server(String address) @@ -1478,7 +1481,7 @@ void set_mqtt_server(String address) /** * @brief Updates the IP address in EEPROM 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. @@ -1493,7 +1496,7 @@ void eeprom_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_ /** * @brief Retrieves an IP address from EEPROM memory. - * + * * @param rom_address The address in EEPROM memory where the IP address is stored. * @return The retrieved IP address. */ @@ -1506,7 +1509,7 @@ IPAddress eeprom_ip_retrieve(uint16_t rom_address) /** * @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) @@ -1517,7 +1520,7 @@ void set_hostname(String hostname) /** * @brief Retrieves the hostname from EEPROM and stores it in the HOSTNAME variable. - * + * */ void eeprom_hostname_retrieve() { @@ -1526,7 +1529,7 @@ void eeprom_hostname_retrieve() /** * @brief Sets the base topic for MQTT communication and writes it to EEPROM. - * + * * @param topic The base topic to set. */ void set_basetopic(String topic) @@ -1537,7 +1540,7 @@ void set_basetopic(String topic) /** * @brief Retrieves the MQTT base topic from EEPROM and stores it in MQTT_BASE_TOPIC array. - * + * */ void eeprom_basetopic_retrieve() { @@ -1546,7 +1549,7 @@ void eeprom_basetopic_retrieve() /** * @brief Sets the MQTT port in the EEPROM. - * + * * @param port The MQTT port to be set. */ void mqtt_port_set(uint16_t port) @@ -1557,7 +1560,7 @@ void mqtt_port_set(uint16_t port) } /** * @brief Retrieves the MQTT port from EEPROM and stores it in the MQTT_PORT variable. - * + * */ void eeprom_mqtt_port_retrieve() { @@ -1568,7 +1571,7 @@ void eeprom_mqtt_port_retrieve() /** * @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. */ @@ -1590,7 +1593,7 @@ uint16_t pwm_get_value(int 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. */ @@ -1611,7 +1614,7 @@ uint8_t ac_get_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() @@ -1620,7 +1623,7 @@ uint8_t ac_get_mode() } /** * @brief Get the current fan speed. - * + * * @return uint8_t The current fan speed. */ uint8_t ac_get_fan_speed() @@ -1631,7 +1634,7 @@ uint8_t ac_get_fan_speed() /** * @brief Retrieves the MQTT username from EEPROM and stores it in the MQTT_USERNAME global variable. - * + * */ void eeprom_mqtt_username_retrieve() { @@ -1639,7 +1642,7 @@ void eeprom_mqtt_username_retrieve() } /** * @brief Retrieves the MQTT password from EEPROM and stores it in the MQTT_PASSWORD global variable. - * + * */ void eeprom_mqtt_password_retrieve() { @@ -1647,7 +1650,7 @@ void eeprom_mqtt_password_retrieve() } /** * @brief Sets the MQTT username and writes it to the EEPROM. - * + * * @param username The MQTT username to set. */ void set_mqtt_username(String username) @@ -1657,7 +1660,7 @@ void set_mqtt_username(String username) } /** * @brief Sets the MQTT password and writes it to the EEPROM. - * + * * @param password The MQTT password to set. */ void set_mqtt_password(String password) @@ -1672,7 +1675,7 @@ void eeprom_mqtt_useauth_retrieve() } /** * @brief Sets the MQTT_USE_AUTH flag and writes it to the EEPROM. - * + * * @param use_auth A boolean value indicating whether to use authentication for MQTT. */ void set_mqtt_useauth(bool use_auth) @@ -1683,10 +1686,10 @@ void set_mqtt_useauth(bool use_auth) /** * @brief Resets the device to factory default settings. - * - * This function resets the device to its factory default settings by formatting the FRAM, + * + * 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() { @@ -1727,9 +1730,9 @@ void factory_reset() /** * @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() { From 02eb63a54c25fd9c1a31b5916ddb70cb69879ef1 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 16 Nov 2023 15:11:52 +0700 Subject: [PATCH 05/25] Update .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8a9fb2f..c748104 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch -.vs/ \ No newline at end of file +.vs/ +.vscode/ +.vscode/settings.json +.vscode/settings.json From 47402e1c71578ce900b01b273117f7862c0e561d Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 16 Nov 2023 15:12:10 +0700 Subject: [PATCH 06/25] Update .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c748104..5c228a4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,4 @@ .vscode/ipch .vs/ .vscode/ -.vscode/settings.json -.vscode/settings.json +.vscode/settings.json \ No newline at end of file From 509f18b7cc281e6e3825d54df938a1ab20394524 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 16 Nov 2023 23:30:46 +0700 Subject: [PATCH 07/25] allow bus overclock --- .vscode/settings.json | 93 ++++++++++++++++++++++++++++++++-------- src/espmega_iot_core.cpp | 6 +++ src/user_code.hpp | 6 +++ 3 files changed, 87 insertions(+), 18 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 69aa100..2975662 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,20 +1,77 @@ { - "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.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 } \ No newline at end of file diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index e797661..af1b163 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -144,6 +144,12 @@ 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(); eeprom_retrieve_init(); user_pre_init(); diff --git a/src/user_code.hpp b/src/user_code.hpp index 2808306..f14d89b 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -6,6 +6,12 @@ #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 + // Enable Software Module(s) #define ENABLE_INTERNAL_LCD #define ENABLE_IR_MODULE From d2610b983f353a0ac33081f7c9de7b5a054e77a7 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 02:18:44 +0700 Subject: [PATCH 08/25] add iot-core support for analog expansion card --- src/espmega_iot_core.cpp | 343 ++++++++++++++++++++++++++++++++++++--- src/espmega_iot_core.hpp | 17 +- src/user_code.hpp | 4 + 3 files changed, 341 insertions(+), 23 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index af1b163..a997d5d 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -92,23 +92,43 @@ char AC_ROOM_TEMPERATURE_TOPIC[75]; char AC_HUMIDITY_TOPIC[75]; #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 + // 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 +#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 +#define EEPROM_ADDRESS_ADC_REPORT_STATE 187 // 8bytes, thru 194 +#define EEPROM_ADDRESS_DAC_STATE 195 // 4bytes, thru 198 +#define EEPROM_ADDRESS_DAC_VALUE 199 // 8bytes, thru 206 char PWM_STATE_TOPIC[75]; char PWM_VALUE_TOPIC[75]; @@ -125,7 +145,8 @@ Thread mqtt_reconnector = Thread(); Thread environment_reporter = Thread(); Thread eeprom_pwm_updater = Thread(); Thread user_timer_tick = Thread(); -StaticThreadController<4> thread_controller(&mqtt_reconnector, &environment_reporter, &eeprom_pwm_updater, &user_timer_tick); +Thread analog_handler = Thread(); +StaticThreadController<5> thread_controller(&mqtt_reconnector, &environment_reporter, &eeprom_pwm_updater, &user_timer_tick, &analog_handler); #ifdef ENABLE_INTERNAL_LCD Thread top_bar_updater = Thread(); @@ -144,12 +165,12 @@ void setup() #endif Serial.println("ESPMega R3 Initializing"); ESPMega_begin(); - #ifdef OVERCLOCK_FM2 +#ifdef OVERCLOCK_FM2 Wire.setClock(1000000); - #endif - #ifdef OVERCLOCK_FM +#endif +#ifdef OVERCLOCK_FM Wire.setClock(400000); - #endif +#endif io_begin(); eeprom_retrieve_init(); user_pre_init(); @@ -297,6 +318,30 @@ void eeprom_retrieve_init() strcat(PWM_VALUE_TOPIC, "/pwm/00/value"); memcpy(INPUTS_TOPIC, MQTT_BASE_TOPIC, 20); strcat(INPUTS_TOPIC, "/input/00"); +#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(EEPROM_ADDRESS_ADC_REPORT_STATE, (uint8_t *)adc_report_enable, 8); + ESPMega_FRAM.read(EEPROM_ADDRESS_DAC_STATE, (uint8_t *)dac_states, 4); + ESPMega_FRAM.read(EEPROM_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 @@ -572,6 +617,23 @@ void mqtt_subscribe() mqtt.subscribe(AC_SET_MODE_TOPIC); #endif mqtt.subscribe(STATE_REQUEST_TOPIC); +#ifdef ENABLE_ANALOG_MODULE + for (int i = 0; i < ADC_COUNT; i++) + { + ADC_COMMAND_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0'; + ADC_COMMAND_TOPIC[base_topic_length + 5] = (i % 10) + '0'; + mqtt.subscribe(ADC_COMMAND_TOPIC); + } + for (int i = 0; i < DAC_COUNT; i++) + { + DAC_SET_STATE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0'; + DAC_SET_STATE_TOPIC[base_topic_length + 5] = (i % 10) + '0'; + DAC_SET_VALUE_TOPIC[base_topic_length + 4] = ((i - i % 10) / 10) + '0'; + DAC_SET_VALUE_TOPIC[base_topic_length + 5] = (i % 10) + '0'; + mqtt.subscribe(DAC_SET_STATE_TOPIC); + mqtt.subscribe(DAC_SET_VALUE_TOPIC); + } +#endif } /** @@ -597,6 +659,20 @@ void mqtt_callback(char *topic, byte *payload, unsigned int length) { pwm_value_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 else if (!strcmp(topic, STATE_REQUEST_TOPIC)) { state_request_callback(); @@ -628,6 +704,10 @@ void thread_initialization() 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 } /** @@ -1747,4 +1827,223 @@ void check_boot_reset() { factory_reset(); } -} \ No newline at end of file +} + +#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(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 1); +} +/** + * @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 EEPROM. + * + * @param id The ID of the ADC to disable reporting for. + */ +void disable_adc(int id) +{ + adc_report_enable[id] = false; + ESPMega_FRAM.write8(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 0); +} +/** + * @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_all_adc(); +} + +/** + * Publishes the ADC value to the MQTT broker. + * + * @param id The ID of the ADC channel. + */ +void publish_adc(int id) +{ + ADC_STATE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0'; + ADC_STATE_TOPIC[base_topic_length + 5] = (id % 10) + '0'; + char temp[6]; + itoa(adc_values[id], temp, DEC); + mqtt.publish(ADC_STATE_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_all_adc() +{ + for (int i = 0; i < ADC_COUNT; i++) + { + if (adc_report_enable[i]) + publish_adc(i); + } +} +/** + * @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[4] - '0'; + int b = topic[5] - '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(EEPROM_ADDRESS_DAC_VALUE + id * 2, dac_values[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 EEPROM 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(EEPROM_ADDRESS_DAC_STATE + id, dac_states[id]); +} + +/** + * @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[4] - '0'; + int b = topic[5] - '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[4] - '0'; + int b = topic[5] - '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); + } +} +#endif diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp index f542632..a2eb29f 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -131,4 +131,19 @@ void eeprom_mqtt_useauth_retrieve(); void set_mqtt_useauth(bool use_auth); void factory_reset(); -void check_boot_reset(); \ No newline at end of file +void check_boot_reset(); + +void enable_adc(int id); +void disable_adc(int id); +void adc_update(int id); +void adc_update_force(int id); +void adc_update_all(); +void adc_loop(); +void publish_adc(int id); +void publish_all_adc(); +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); diff --git a/src/user_code.hpp b/src/user_code.hpp index f14d89b..0e04793 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -16,6 +16,7 @@ #define ENABLE_INTERNAL_LCD #define ENABLE_IR_MODULE #define ENABLE_CLIMATE_MODULE // Require IR Module +#define ENABLE_ANALOG_MODULE #define ENABLE_WEBUI // Infrared Transciever @@ -35,6 +36,9 @@ #define ESPMega_EXTLCD Serial2 #endif +// Analog Module Configuration +#define ANALOG_REPORTING_INTERVAL 500 + // User Defined Functions void user_pre_init(); void user_init(); From 1010dae0e69325b206232fe31198b710298af635 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 02:15:43 -0800 Subject: [PATCH 09/25] Add readme.md --- readme.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 readme.md diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..16792ca --- /dev/null +++ b/readme.md @@ -0,0 +1,18 @@ +# 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 \ No newline at end of file From bb0838ad3048763a14054f9651f90fb961f6edd6 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 02:16:06 -0800 Subject: [PATCH 10/25] Update readme.md --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 16792ca..ffcefb2 100644 --- a/readme.md +++ b/readme.md @@ -2,14 +2,14 @@ This is an OS for the ESPMega PRO R3 Programable Logic Controller ## **Compatibility** -1. CPU +1. **CPU** - ESPMega PRO R3.0a/b - ESPMega PRO R3.1a - ESPMega PRO R3.2a/b/c -2. CPU Add-ons +2. **CPU Add-ons** - ESPMega PRO Internal Display Module - ESPMega PRO External Touch Display Module -3. Add-on Cards +3. **Add-on Cards** - ESPMega I/O Analog Expansion Card - ESPMega I/O IR Expansion Kit - ESPMega I/O Card Hub From 557df3333ec7b1714ed9b33407401876cf4d626e Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 02:28:13 -0800 Subject: [PATCH 11/25] Update readme.md --- readme.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index ffcefb2..b0a4f7e 100644 --- a/readme.md +++ b/readme.md @@ -15,4 +15,21 @@ This is an OS for the ESPMega PRO R3 Programable Logic Controller - ESPMega I/O Card Hub - ESPMega I/O UART Multiplexer [WIP] - ESPMega I/O Digital Expansion Card [WIP] -## Features \ No newline at end of file + +## 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 From 549500822ccda0edb839a3637fc72e7dead8d03a Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 18:53:01 +0700 Subject: [PATCH 12/25] update state publishing --- src/espmega_iot_core.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/espmega_iot_core.hpp | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index a997d5d..303df07 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -579,6 +579,9 @@ void mqtt_connect() publish_ac_state(); #endif mqtt_connected_user_callback(); + publish_dac_states(); + publish_dac_values(); + publish_all_adc(); standalone = false; ESPMega_updateTimeFromNTP(); } @@ -1004,6 +1007,9 @@ void state_request_callback() publish_env_state(); #endif user_state_request_callback(); + publish_all_adc(); + publish_dac_states(); + publish_dac_values(); } #ifdef ENABLE_IR_MODULE @@ -1929,6 +1935,22 @@ void publish_all_adc() publish_adc(i); } } + +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"); +} + +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. * @@ -1987,6 +2009,7 @@ void dac_set_value(int id, int value) dac_values[id] = value; ESPMega_dacWrite(id, dac_values[id] * dac_states[id]); ESPMega_FRAM.write16(EEPROM_ADDRESS_DAC_VALUE + id * 2, dac_values[id]); + publish_dac_value(id); } /** @@ -2003,6 +2026,23 @@ void dac_set_state(int id, bool state) dac_states[id] = state; ESPMega_dacWrite(id, dac_values[id] * dac_states[id]); ESPMega_FRAM.write8(EEPROM_ADDRESS_DAC_STATE + id, dac_states[id]); + publish_dac_state(id); +} + +void publish_dac_states() +{ + for (int i = 0; i < DAC_COUNT; i++) + { + publish_dac_state(i); + } +} + +void publish_dac_values() +{ + for (int i = 0; i < DAC_COUNT; i++) + { + publish_dac_value(i); + } } /** diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp index a2eb29f..9e48e06 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -147,3 +147,7 @@ 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(); \ No newline at end of file From 62f774964d04a074bea5602d873957889062767f Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 19:44:05 +0700 Subject: [PATCH 13/25] fix adc reporting bug --- src/espmega_iot_core.cpp | 55 ++++++++++++++++++++++++++++------------ src/espmega_iot_core.hpp | 8 +++--- src/user_code.hpp | 2 +- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 303df07..cf087c2 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -581,7 +581,7 @@ void mqtt_connect() mqtt_connected_user_callback(); publish_dac_states(); publish_dac_values(); - publish_all_adc(); + publish_adc_values(); standalone = false; ESPMega_updateTimeFromNTP(); } @@ -1007,7 +1007,7 @@ void state_request_callback() publish_env_state(); #endif user_state_request_callback(); - publish_all_adc(); + publish_adc_values(); publish_dac_states(); publish_dac_values(); } @@ -1845,6 +1845,8 @@ void enable_adc(int id) { adc_report_enable[id] = true; ESPMega_FRAM.write8(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 1); + publish_adc_state(id); + Serial.println("ADC " + String(id) + " enabled."); } /** * @brief Disables the ADC reporting for the specified ID. @@ -1857,7 +1859,25 @@ void disable_adc(int id) { adc_report_enable[id] = false; ESPMega_FRAM.write8(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 0); + publish_adc_state(id); + Serial.println("ADC " + String(id) + " disabled."); } + +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"); +} + +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. * @@ -1869,6 +1889,7 @@ void adc_update(int id) { adc_values[id] = ESPMega_analogRead(id); } + } /** @@ -1905,7 +1926,7 @@ void adc_update_all() void adc_loop() { adc_update_all(); - publish_all_adc(); + publish_adc_values(); } /** @@ -1913,13 +1934,13 @@ void adc_loop() * * @param id The ID of the ADC channel. */ -void publish_adc(int id) +void publish_adc_value(int id) { - ADC_STATE_TOPIC[base_topic_length + 4] = ((id - id % 10) / 10) + '0'; - ADC_STATE_TOPIC[base_topic_length + 5] = (id % 10) + '0'; - char temp[6]; + 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_STATE_TOPIC, temp); + mqtt.publish(ADC_REPORT_TOPIC, temp); } /** @@ -1927,12 +1948,12 @@ void publish_adc(int id) * This function iterates through all ADC channels and publishes the values * of the enabled channels using the publish_adc() function. */ -void publish_all_adc() +void publish_adc_values() { for (int i = 0; i < ADC_COUNT; i++) { if (adc_report_enable[i]) - publish_adc(i); + publish_adc_value(i); } } @@ -1980,9 +2001,11 @@ uint16_t get_adc_value(int id) */ void adc_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) { - int a = topic[4] - '0'; - int b = topic[5] - '0'; + Serial.println(topic); + int a = topic[5] - '0'; + int b = topic[6] - '0'; int id = 10 * a + b; + Serial.println("ID = "+String(id)); if (!strcmp(payload, "on")) { enable_adc(id); @@ -2055,8 +2078,8 @@ void publish_dac_values() */ void dac_set_value_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) { - int a = topic[4] - '0'; - int b = topic[5] - '0'; + int a = topic[5] - '0'; + int b = topic[6] - '0'; int id = 10 * a + b; int value = atoi(payload); dac_set_value(id, value); @@ -2074,8 +2097,8 @@ void dac_set_value_callback(char *topic, uint8_t topic_length, char *payload, un */ void dac_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) { - int a = topic[4] - '0'; - int b = topic[5] - '0'; + int a = topic[5] - '0'; + int b = topic[6] - '0'; int id = 10 * a + b; if (!strcmp(payload, "on")) { diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp index 9e48e06..531735a 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -139,8 +139,8 @@ void adc_update(int id); void adc_update_force(int id); void adc_update_all(); void adc_loop(); -void publish_adc(int id); -void publish_all_adc(); +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); @@ -150,4 +150,6 @@ void dac_set_state_callback(char *topic, uint8_t topic_length, char *payload, un void publish_dac_value(int id); void publish_dac_state(int id); void publish_dac_values(); -void publish_dac_states(); \ No newline at end of file +void publish_dac_states(); +void publish_adc_state(int id); +void publish_adc_states(); \ No newline at end of file diff --git a/src/user_code.hpp b/src/user_code.hpp index 0e04793..b6206e2 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -13,7 +13,7 @@ //#define OVERCLOCK_FM2 // Enable Software Module(s) -#define ENABLE_INTERNAL_LCD +//#define ENABLE_INTERNAL_LCD #define ENABLE_IR_MODULE #define ENABLE_CLIMATE_MODULE // Require IR Module #define ENABLE_ANALOG_MODULE From ef43526d2cfa6d2dff20fade549426a2083797b9 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 19:46:58 +0700 Subject: [PATCH 14/25] cleanup debug prints --- src/espmega_iot_core.cpp | 47 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index cf087c2..e8713c9 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -579,9 +579,12 @@ void mqtt_connect() publish_ac_state(); #endif mqtt_connected_user_callback(); +#ifdef ENABLE_ANALOG_MODULE publish_dac_states(); publish_dac_values(); publish_adc_values(); + publish_adc_states(); +#endif standalone = false; ESPMega_updateTimeFromNTP(); } @@ -1007,9 +1010,12 @@ void state_request_callback() 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 @@ -1846,7 +1852,6 @@ void enable_adc(int id) adc_report_enable[id] = true; ESPMega_FRAM.write8(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 1); publish_adc_state(id); - Serial.println("ADC " + String(id) + " enabled."); } /** * @brief Disables the ADC reporting for the specified ID. @@ -1860,7 +1865,6 @@ void disable_adc(int id) adc_report_enable[id] = false; ESPMega_FRAM.write8(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 0); publish_adc_state(id); - Serial.println("ADC " + String(id) + " disabled."); } void publish_adc_state(int id) @@ -1880,7 +1884,7 @@ void publish_adc_states() /** * @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) @@ -1889,12 +1893,11 @@ void adc_update(int 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) @@ -1902,12 +1905,11 @@ 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() @@ -1920,7 +1922,7 @@ void adc_update_all() /** * @brief Performs ADC loop operations. - * + * * This function updates all ADC values and publishes them. */ void adc_loop() @@ -1931,7 +1933,7 @@ void adc_loop() /** * Publishes the ADC value to the MQTT broker. - * + * * @param id The ID of the ADC channel. */ void publish_adc_value(int id) @@ -1964,7 +1966,8 @@ void publish_dac_state(int id) mqtt.publish(DAC_STATE_TOPIC, dac_states[id] ? "on" : "off"); } -void publish_dac_value(int id) { +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]; @@ -1974,10 +1977,10 @@ void publish_dac_value(int id) { /** * @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. */ @@ -1990,10 +1993,10 @@ uint16_t get_adc_value(int 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. @@ -2001,11 +2004,9 @@ uint16_t get_adc_value(int id) */ void adc_set_state_callback(char *topic, uint8_t topic_length, char *payload, unsigned int payload_length) { - Serial.println(topic); int a = topic[5] - '0'; int b = topic[6] - '0'; int id = 10 * a + b; - Serial.println("ID = "+String(id)); if (!strcmp(payload, "on")) { enable_adc(id); @@ -2018,12 +2019,12 @@ void adc_set_state_callback(char *topic, uint8_t topic_length, char *payload, un /** * @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. */ @@ -2037,10 +2038,10 @@ void dac_set_value(int id, int value) /** * @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 EEPROM for persistence across power cycles. - * + * * @param id The ID of the DAC channel. * @param state The new state of the DAC channel. */ @@ -2086,10 +2087,10 @@ void dac_set_value_callback(char *topic, uint8_t topic_length, char *payload, un } /** * @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. From 38a656ee55f862a81bff24fadf4479c45d960908 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 19:48:52 +0700 Subject: [PATCH 15/25] re enable lcd --- src/user_code.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user_code.hpp b/src/user_code.hpp index b6206e2..0e04793 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -13,7 +13,7 @@ //#define OVERCLOCK_FM2 // Enable Software Module(s) -//#define ENABLE_INTERNAL_LCD +#define ENABLE_INTERNAL_LCD #define ENABLE_IR_MODULE #define ENABLE_CLIMATE_MODULE // Require IR Module #define ENABLE_ANALOG_MODULE From 47f5e325aa2aa9619afaa13baa7727f077ead335 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 19:50:54 +0700 Subject: [PATCH 16/25] move DHT22 pin def --- src/espmega_iot_core.cpp | 1 - src/user_code.hpp | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index e8713c9..64a7450 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -78,7 +78,6 @@ Mode 0: Off, 1: Cool, 2: Fan Fan Speed 0: Auto, 1: High, 2: Mid, 3: Low */ #ifdef ENABLE_CLIMATE_MODULE -#define DHT22_PIN 32 uint8_t ac_mode = 0; uint8_t ac_fan_speed = 0; uint8_t ac_temperature = 25; diff --git a/src/user_code.hpp b/src/user_code.hpp index 0e04793..395a6e4 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -19,13 +19,14 @@ #define ENABLE_ANALOG_MODULE #define ENABLE_WEBUI -// Infrared Transciever +// IR Kit Configuration #define IR_RECIEVE_PIN 35 #define IR_SEND_PIN 17 #define MARK_EXCESS_MICROS 20 #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 From 3b146b3bdf7c43677875d76e8659e57e9212f2d2 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Thu, 30 Nov 2023 20:01:39 +0700 Subject: [PATCH 17/25] refactor and comment --- src/espmega_iot_core.cpp | 76 ++++++++++++++++++++++++++++++++++++++++ src/espmega_iot_core.hpp | 6 +++- src/user_code.hpp | 35 +++++++++++++----- 3 files changed, 108 insertions(+), 9 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 64a7450..e895f15 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -1866,6 +1866,11 @@ void disable_adc(int id) 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'; @@ -1873,6 +1878,11 @@ void publish_adc_state(int id) 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++) @@ -1958,6 +1968,11 @@ void publish_adc_values() } } +/** + * 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'; @@ -1965,6 +1980,11 @@ void publish_dac_state(int id) 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'; @@ -2052,6 +2072,13 @@ void dac_set_state(int id, bool state) 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++) @@ -2060,6 +2087,13 @@ void publish_dac_states() } } +/** + * @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++) @@ -2109,4 +2143,46 @@ void dac_set_state_callback(char *topic, uint8_t topic_length, char *payload, un 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 diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp index 531735a..f0b63af 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -152,4 +152,8 @@ void publish_dac_state(int id); void publish_dac_values(); void publish_dac_states(); void publish_adc_state(int id); -void publish_adc_states(); \ No newline at end of file +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); \ No newline at end of file diff --git a/src/user_code.hpp b/src/user_code.hpp index 395a6e4..9de5311 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -41,18 +41,20 @@ #define ANALOG_REPORTING_INTERVAL 500 // User Defined Functions +void timer1_callback(); +void bt0PopCallback(void *ptr); + +// User Defined IoT Core Callback Functions (Required) +void user_mqtt_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length); +void user_state_request_callback(); +void mqtt_connected_user_callback(); void user_pre_init(); void user_init(); void user_loop(); -void virtual_interrupt_user_callback(int pin, int state); void pwm_changed_user_callback(int pin); void ac_changed_user_callback(int mode, int temperature, int fan_speed); void timer_tick_callback(); -void timer1_callback(); -void mqtt_connected_user_callback(); -void bt0PopCallback(void *ptr); -void user_state_request_callback(); -void user_mqtt_callback(char* topic, uint8_t topic_length, char* payload, unsigned int payload_length); +void virtual_interrupt_user_callback(int pin, int state); // ESPMega IoT Core Build-in Functions extern void pwm_set_state(int id, int state); @@ -64,9 +66,26 @@ extern bool pwm_get_state(int id); extern uint16_t pwm_get_value(int id); extern boolean pwm_group_state(int id1, int id2); extern bool input_get_state(int id); +extern bool standalone; +extern PubSubClient mqtt; + +// IR Kit Build-in Functions +#ifdef ENABLE_IR_MODULE extern void ac_set_state(int mode, int temperature, int fan_speed); extern uint8_t ac_get_temperature(); extern uint8_t ac_get_mode(); extern uint8_t ac_get_fan_speed(); -extern bool standalone; -extern PubSubClient mqtt; \ No newline at end of file +#endif + +//Analog Expansion Card Build-in Functions +#ifdef ENABLE_ANALOG_MODULE +extern void dac_set_value(int id, int value); +extern void dac_set_state(int id, bool state); +extern void enable_adc(int id); +extern void disable_adc(int id); +extern void enable_dac(int id); +extern uint16_t adc_get_value(int id); +extern bool adc_get_state(int id); +extern uint16_t dac_get_value(int id); +extern bool dac_get_state(int id); +#endif \ No newline at end of file From a9181c90e6e1a064595df059f937f0e7838e03c1 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sat, 2 Dec 2023 01:25:36 +0700 Subject: [PATCH 18/25] allow sending infrared signal through MQTT --- src/espmega_iot_core.cpp | 17 +++++++++++++++++ src/user_code.hpp | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index e895f15..f61b243 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -91,6 +91,11 @@ 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 @@ -677,6 +682,18 @@ void mqtt_callback(char *topic, byte *payload, unsigned int length) { 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)) { diff --git a/src/user_code.hpp b/src/user_code.hpp index 9de5311..31f026c 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -23,7 +23,7 @@ #define IR_RECIEVE_PIN 35 #define IR_SEND_PIN 17 #define MARK_EXCESS_MICROS 20 -#define RAW_BUFFER_LENGTH 750 +#define IR_RAW_BUFFER_LENGTH 750 #define AC_MAX_TEMPERATURE 30 #define AC_MIN_TEMPERATURE 15 #define DHT22_PIN 32 From e3c07411cbcd7d2dd1dca9ef06b17b785e3ad070 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sat, 2 Dec 2023 21:06:46 +0700 Subject: [PATCH 19/25] allow preloading virtual interrupt buffer --- src/espmega_iot_core.cpp | 9 +++++++++ src/espmega_iot_core.hpp | 1 + src/user_code.hpp | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index e895f15..c2267d1 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -171,6 +171,9 @@ void setup() Wire.setClock(400000); #endif io_begin(); +#ifdef VIRTUAL_INTERRUPT_PRELOAD + virtual_interrupt_preload(); +#endif eeprom_retrieve_init(); user_pre_init(); #ifdef ENABLE_INTERNAL_LCD @@ -2186,3 +2189,9 @@ bool dac_get_state(int 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 f0b63af..bf277ec 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -46,6 +46,7 @@ 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(); diff --git a/src/user_code.hpp b/src/user_code.hpp index 9de5311..94f92b5 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -12,6 +12,9 @@ //#define OVERCLOCK_FM //#define OVERCLOCK_FM2 +// I/O Configuration +#define VIRTUAL_INTERRUPT_PRELOAD // Preload Virtual Interrupts buffer + // Enable Software Module(s) #define ENABLE_INTERNAL_LCD #define ENABLE_IR_MODULE From 192b1468f8d7004b9e9205aaca948cedd5529cf0 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sun, 3 Dec 2023 00:37:24 +0700 Subject: [PATCH 20/25] publish availability --- src/espmega_iot_core.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index c2267d1..ca29b47 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -32,6 +32,7 @@ WebServer otaserver(80); #endif bool standalone = true; char MQTT_BASE_TOPIC[20]; +char AVAILABILITY_TOPIC[40]; uint8_t base_topic_length = 0; char STATE_REQUEST_TOPIC[40]; bool MQTT_USE_AUTH = false; @@ -237,6 +238,7 @@ void loop() */ void eeprom_retrieve_init() { + // EEPROM Data Retrival #ifdef ENABLE_CLIMATE_MODULE ac_mode = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_MODE); @@ -320,6 +322,8 @@ void eeprom_retrieve_init() strcat(PWM_VALUE_TOPIC, "/pwm/00/value"); memcpy(INPUTS_TOPIC, MQTT_BASE_TOPIC, 20); strcat(INPUTS_TOPIC, "/input/00"); + memcpy(AVAILABILITY_TOPIC, MQTT_BASE_TOPIC, 20); + strcat(AVAILABILITY_TOPIC, "/availability"); #ifdef ENABLE_ANALOG_MODULE memcpy(ADC_COMMAND_TOPIC, MQTT_BASE_TOPIC, 20); strcat(ADC_COMMAND_TOPIC, "/adc/00/set/state"); @@ -567,13 +571,14 @@ void mqtt_connect() Serial.print("MQTT not connected, connecting . . .\n"); lcd_send_stop_bit(); if (MQTT_USE_AUTH) - mqtt.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD); + mqtt.connect(HOSTNAME, MQTT_USERNAME, MQTT_PASSWORD, AVAILABILITY_TOPIC, 0, true, "offline"); else - mqtt.connect(HOSTNAME); + mqtt.connect(HOSTNAME, AVAILABILITY_TOPIC, 0, true, "offline"); if (mqtt.connected()) { mqtt_subscribe(); Serial.print("MQTT connected\n"); + mqtt.publish(AVAILABILITY_TOPIC, "online", true); lcd_send_stop_bit(); publish_pwm_states(); publish_input_states(); From 9e2efddfc93d5071c00f2ff7ac0aed7a0a1744c5 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sun, 3 Dec 2023 02:34:37 +0700 Subject: [PATCH 21/25] http authentication support --- src/espmega_iot_core.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index ca29b47..3d4625d 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -38,6 +38,10 @@ 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; @@ -129,6 +133,8 @@ char DAC_VALUE_TOPIC[75]; #define EEPROM_ADDRESS_ADC_REPORT_STATE 187 // 8bytes, thru 194 #define EEPROM_ADDRESS_DAC_STATE 195 // 4bytes, thru 198 #define EEPROM_ADDRESS_DAC_VALUE 199 // 8bytes, thru 206 +#define EEPROM_ADDRESS_WEBUI_USERNAME 207 // 32bytes, thru 238 +#define EEPROM_ADDRESS_WEBUI_PASSWORD 239 // 32bytes, thru 270 char PWM_STATE_TOPIC[75]; char PWM_VALUE_TOPIC[75]; @@ -238,7 +244,10 @@ void loop() */ void eeprom_retrieve_init() { - + #ifdef ENABLE_WEBUI + ESPMega_FRAM.read(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); + ESPMega_FRAM.read(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); + #endif // EEPROM Data Retrival #ifdef ENABLE_CLIMATE_MODULE ac_mode = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_MODE); @@ -365,6 +374,8 @@ 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; @@ -382,6 +393,8 @@ void ota_begin() otaserver.send(200, "text/html", otabuffer); }); otaserver.on("/config", HTTP_GET, []() { + if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD)) + return otaserver.requestAuthentication(); otaserver.sendHeader("Connection", "close"); String configbuffer = config_part1; configbuffer+=config_txt_part1+"IP Address"+config_txt_part2+"text"+config_txt_part3+"dev_ip"+config_txt_part4+"dev_ip"+config_txt_part5+IP.toString()+config_txt_part6; @@ -395,11 +408,15 @@ void ota_begin() configbuffer+=config_txt_part1+"BMS Server - Username"+config_txt_part2+"text"+config_txt_part3+"bms_username"+config_txt_part4+"bms_username"+config_txt_part5+String(MQTT_USERNAME)+config_txt_part6; configbuffer+=config_txt_part1+"BMS Server - Password"+config_txt_part2+"password"+config_txt_part3+"bms_password"+config_txt_part4+"bms_password"+config_txt_part5+String(MQTT_PASSWORD)+config_txt_part6; configbuffer+=config_txt_part1+"BMS Server - Endpoint"+config_txt_part2+"text"+config_txt_part3+"bms_endpoint"+config_txt_part4+"bms_endpoint"+config_txt_part5+String(MQTT_BASE_TOPIC)+config_txt_part6; + configbuffer+=config_txt_part1+"WebUI Username"+config_txt_part2+"text"+config_txt_part3+"webui_username"+config_txt_part4+"webui_username"+config_txt_part5+String(WEBUI_USERNAME)+config_txt_part6; + configbuffer+=config_txt_part1+"WebUI Password"+config_txt_part2+"password"+config_txt_part3+"webui_password"+config_txt_part4+"webui_password"+config_txt_part5+String(WEBUI_PASSWORD)+config_txt_part6; configbuffer+=config_part2; otaserver.send(200, "text/html", configbuffer); }); otaserver.on("/save_config", HTTP_GET, []() { + if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD)) + return otaserver.requestAuthentication(); otaserver.sendHeader("Connection", "close"); String configbuffer = "Configuration Saved. Rebooting . . ."; otaserver.send(200, "text/html", configbuffer); @@ -432,6 +449,10 @@ void ota_begin() } else if(!arg.compareTo("bms_useauth")) { if(!value.compareTo("yes")) use_auth = true; + } else if(!arg.compareTo("webui_username")) { + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)value.c_str(), value.length()); + } else if(!arg.compareTo("webui_password")) { + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)value.c_str(), value.length()); } } set_mqtt_useauth(use_auth); @@ -442,6 +463,8 @@ void ota_begin() otaserver.on( "/update", HTTP_POST, []() { + if(!otaserver.authenticate(WEBUI_USERNAME, WEBUI_PASSWORD)) + return otaserver.requestAuthentication(); otaserver.sendHeader("Connection", "close"); otaserver.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); ESP.restart(); }, @@ -1789,6 +1812,18 @@ void set_mqtt_useauth(bool use_auth) ESPMega_FRAM.write8(EEPROM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH); } +void set_webui_username(String username) +{ + username.toCharArray(WEBUI_USERNAME, 32); + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); +} + +void set_webui_password(String password) +{ + password.toCharArray(WEBUI_PASSWORD, 32); + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); +} + /** * @brief Resets the device to factory default settings. * @@ -1824,6 +1859,9 @@ void factory_reset() set_ip("192.168.0.10"); set_gw("192.168.0.1"); set_netmask("255.255.255.0"); + set_webui_username("admin"); + set_webui_password("admin"); + // Reboot #ifdef ENABLE_INTERNAL_LCD lcd_send_stop_bit(); From dae545a63eab2895f730edc552756c26fa514364 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sun, 3 Dec 2023 02:37:50 +0700 Subject: [PATCH 22/25] automatically initialize new device with webui username and password --- src/espmega_iot_core.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 3d4625d..50e1bd4 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -247,6 +247,14 @@ void eeprom_retrieve_init() #ifdef ENABLE_WEBUI ESPMega_FRAM.read(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); ESPMega_FRAM.read(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); + if(strlen(WEBUI_USERNAME)==0) { + strcpy(WEBUI_USERNAME,"admin"); + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); + } + if(strlen(WEBUI_PASSWORD)==0) { + strcpy(WEBUI_PASSWORD,"admin"); + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); + } #endif // EEPROM Data Retrival #ifdef ENABLE_CLIMATE_MODULE From d489126f1423e6b7265293cc954c3dd75ae03c34 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sun, 3 Dec 2023 14:52:04 +0700 Subject: [PATCH 23/25] add null termination when writing http auth info --- src/espmega_iot_core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 50e1bd4..b1d9ae8 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -458,9 +458,9 @@ void ota_begin() if(!value.compareTo("yes")) use_auth = true; } else if(!arg.compareTo("webui_username")) { - ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)value.c_str(), value.length()); + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)value.c_str(), value.length()+1); } else if(!arg.compareTo("webui_password")) { - ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)value.c_str(), value.length()); + ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)value.c_str(), value.length()+1); } } set_mqtt_useauth(use_auth); From 010c92fc176b7d3ea94c31437ef3fbdafcb3acfe Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sun, 3 Dec 2023 15:23:00 +0700 Subject: [PATCH 24/25] rename all mention of EEPROM to FRAM --- src/espmega_iot_core.cpp | 246 +++++++++++++++++++-------------------- src/espmega_iot_core.hpp | 20 ++-- 2 files changed, 133 insertions(+), 133 deletions(-) diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index 36aca44..ddfcaf2 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -59,9 +59,9 @@ unsigned long virtual_interupt_timer[VINT_COUNT]; #define PWM_COUNT 16 const uint8_t pwm_pins[PWM_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; bool pwm_states[PWM_COUNT]; -uint8_t pwm_states_eeprom[PWM_COUNT]; +uint8_t pwm_states_fram[PWM_COUNT]; uint16_t pwm_values[PWM_COUNT]; -uint8_t pwm_values_eeprom[PWM_COUNT * 2]; +uint8_t pwm_values_fram[PWM_COUNT * 2]; // output = m*input+c const float pwm_linear_scaling_m[PWM_COUNT] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; const float pwm_linear_scaling_c[PWM_COUNT] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -118,28 +118,28 @@ char DAC_STATE_TOPIC[75]; char DAC_VALUE_TOPIC[75]; #endif -// EEPROM ADDRESS -#define EEPROM_ADDRESS_AC_MODE 0 // 01bytes -#define EEPROM_ADDRESS_AC_TEMPERATURE 1 // 01bytes -#define EEPROM_ADDRESS_AC_FAN_SPEED 2 // 01bytes -#define EEPROM_ADDRESS_PWM_STATE 3 // 16bytes, thru 18 -#define EEPROM_ADDRESS_PWM_VALUE 19 // 32bytes, thru 50 -#define EEPROM_ADDRESS_HOSTNAME 65 // 15bytes, thru 79 -#define EEPROM_ADDRESS_TOPIC 80 // 20bytes, thru 99 -#define EEPROM_ADDRESS_IP 100 // 04bytes, thru 103 -#define EEPROM_ADDRESS_SUBNET 104 // 04bytes, thru 107 -#define EEPROM_ADDRESS_GATEWAY 108 // 04bytes, thru 111 -#define EEPROM_ADDRESS_DNS 112 // 04bytes, thru 115 -#define EEPROM_ADDRESS_MQTT_SERVER 116 // 04bytes, thru 119 -#define EEPROM_ADDRESS_MQTT_PORT 120 // 02bytes, thru 121 -#define EEPROM_ADDRESS_MQTT_USERNAME 122 // 32bytes, thru 153 -#define EEPROM_ADDRESS_MQTT_PASSWORD 154 // 32bytes, thru 185 -#define EEPROM_ADDRESS_MQTT_USEAUTH 186 // 1bytes -#define EEPROM_ADDRESS_ADC_REPORT_STATE 187 // 8bytes, thru 194 -#define EEPROM_ADDRESS_DAC_STATE 195 // 4bytes, thru 198 -#define EEPROM_ADDRESS_DAC_VALUE 199 // 8bytes, thru 206 -#define EEPROM_ADDRESS_WEBUI_USERNAME 207 // 32bytes, thru 238 -#define EEPROM_ADDRESS_WEBUI_PASSWORD 239 // 32bytes, thru 270 +// FRAM ADDRESS +#define FRAM_ADDRESS_AC_MODE 0 // 01bytes +#define FRAM_ADDRESS_AC_TEMPERATURE 1 // 01bytes +#define FRAM_ADDRESS_AC_FAN_SPEED 2 // 01bytes +#define FRAM_ADDRESS_PWM_STATE 3 // 16bytes, thru 18 +#define FRAM_ADDRESS_PWM_VALUE 19 // 32bytes, thru 50 +#define FRAM_ADDRESS_HOSTNAME 65 // 15bytes, thru 79 +#define FRAM_ADDRESS_TOPIC 80 // 20bytes, thru 99 +#define FRAM_ADDRESS_IP 100 // 04bytes, thru 103 +#define FRAM_ADDRESS_SUBNET 104 // 04bytes, thru 107 +#define FRAM_ADDRESS_GATEWAY 108 // 04bytes, thru 111 +#define FRAM_ADDRESS_DNS 112 // 04bytes, thru 115 +#define FRAM_ADDRESS_MQTT_SERVER 116 // 04bytes, thru 119 +#define FRAM_ADDRESS_MQTT_PORT 120 // 02bytes, thru 121 +#define FRAM_ADDRESS_MQTT_USERNAME 122 // 32bytes, thru 153 +#define FRAM_ADDRESS_MQTT_PASSWORD 154 // 32bytes, thru 185 +#define FRAM_ADDRESS_MQTT_USEAUTH 186 // 1bytes +#define FRAM_ADDRESS_ADC_REPORT_STATE 187 // 8bytes, thru 194 +#define FRAM_ADDRESS_DAC_STATE 195 // 4bytes, thru 198 +#define FRAM_ADDRESS_DAC_VALUE 199 // 8bytes, thru 206 +#define FRAM_ADDRESS_WEBUI_USERNAME 207 // 32bytes, thru 238 +#define FRAM_ADDRESS_WEBUI_PASSWORD 239 // 32bytes, thru 270 char PWM_STATE_TOPIC[75]; char PWM_VALUE_TOPIC[75]; @@ -154,10 +154,10 @@ DHTNEW env_sensor(DHT22_PIN); Thread mqtt_reconnector = Thread(); Thread environment_reporter = Thread(); -Thread eeprom_pwm_updater = Thread(); +Thread fram_pwm_updater = Thread(); Thread user_timer_tick = Thread(); Thread analog_handler = Thread(); -StaticThreadController<5> thread_controller(&mqtt_reconnector, &environment_reporter, &eeprom_pwm_updater, &user_timer_tick, &analog_handler); +StaticThreadController<5> thread_controller(&mqtt_reconnector, &environment_reporter, &fram_pwm_updater, &user_timer_tick, &analog_handler); #ifdef ENABLE_INTERNAL_LCD Thread top_bar_updater = Thread(); @@ -186,7 +186,7 @@ void setup() #ifdef VIRTUAL_INTERRUPT_PRELOAD virtual_interrupt_preload(); #endif - eeprom_retrieve_init(); + fram_retrieve_init(); user_pre_init(); #ifdef ENABLE_INTERNAL_LCD lcd_send_stop_bit(); @@ -244,52 +244,52 @@ void loop() } /** - * @brief Retrieves data from EEPROM and initializes various variables and topics. + * @brief Retrieves data from FRAM and initializes various variables and topics. * */ -void eeprom_retrieve_init() +void fram_retrieve_init() { #ifdef ENABLE_WEBUI - ESPMega_FRAM.read(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); - ESPMega_FRAM.read(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); + 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(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); + ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_USERNAME, (uint8_t *)WEBUI_USERNAME, 32); } if(strlen(WEBUI_PASSWORD)==0) { strcpy(WEBUI_PASSWORD,"admin"); - ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); + ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); } #endif -// EEPROM Data Retrival +// FRAM Data Retrival #ifdef ENABLE_CLIMATE_MODULE - ac_mode = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_MODE); - ac_temperature = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_TEMPERATURE); - ac_fan_speed = ESPMega_FRAM.read8(EEPROM_ADDRESS_AC_FAN_SPEED); + ac_mode = ESPMega_FRAM.read8(FRAM_ADDRESS_AC_MODE); + ac_temperature = ESPMega_FRAM.read8(FRAM_ADDRESS_AC_TEMPERATURE); + ac_fan_speed = ESPMega_FRAM.read8(FRAM_ADDRESS_AC_FAN_SPEED); #endif -// EEPROM Data Retrival Validation +// FRAM Data Retrival Validation #ifdef ENABLE_CLIMATE_MODULE if (ac_mode > 2) { ac_mode = 0; - ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_MODE, ac_mode); + ESPMega_FRAM.write8(FRAM_ADDRESS_AC_MODE, ac_mode); } if (ac_temperature > AC_MAX_TEMPERATURE || ac_temperature < AC_MIN_TEMPERATURE) { ac_temperature = AC_MAX_TEMPERATURE; - ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_temperature); + ESPMega_FRAM.write8(FRAM_ADDRESS_AC_TEMPERATURE, ac_temperature); } if (ac_fan_speed > 3) { ac_fan_speed = 0; - ESPMega_FRAM.write8(EEPROM_ADDRESS_AC_TEMPERATURE, ac_fan_speed); + ESPMega_FRAM.write8(FRAM_ADDRESS_AC_TEMPERATURE, ac_fan_speed); } ac_set_state(ac_mode, ac_temperature, ac_fan_speed); #endif - ESPMega_FRAM.read(EEPROM_ADDRESS_PWM_STATE, pwm_states_eeprom, 16); - memcpy(pwm_states, pwm_states_eeprom, 16); - ESPMega_FRAM.read(EEPROM_ADDRESS_PWM_VALUE, pwm_values_eeprom, 32); - memcpy(pwm_values, pwm_values_eeprom, 32); + ESPMega_FRAM.read(FRAM_ADDRESS_PWM_STATE, pwm_states_fram, 16); + memcpy(pwm_states, pwm_states_fram, 16); + ESPMega_FRAM.read(FRAM_ADDRESS_PWM_VALUE, pwm_values_fram, 32); + memcpy(pwm_values, pwm_values_fram, 32); for (int i = 0; i < 15; i++) { if (pwm_states[i] <= 1) @@ -301,18 +301,18 @@ void eeprom_retrieve_init() else pwm_set_value(i, 0); } - IP = eeprom_ip_retrieve(EEPROM_ADDRESS_IP); - SUBNET = eeprom_ip_retrieve(EEPROM_ADDRESS_SUBNET); - GATEWAY = eeprom_ip_retrieve(EEPROM_ADDRESS_GATEWAY); - DNS = eeprom_ip_retrieve(EEPROM_ADDRESS_DNS); - MQTT_SERVER = eeprom_ip_retrieve(EEPROM_ADDRESS_MQTT_SERVER); - eeprom_hostname_retrieve(); - eeprom_mqtt_port_retrieve(); - eeprom_mqtt_useauth_retrieve(); - eeprom_mqtt_username_retrieve(); - eeprom_mqtt_password_retrieve(); + IP = fram_ip_retrieve(FRAM_ADDRESS_IP); + SUBNET = fram_ip_retrieve(FRAM_ADDRESS_SUBNET); + GATEWAY = fram_ip_retrieve(FRAM_ADDRESS_GATEWAY); + DNS = fram_ip_retrieve(FRAM_ADDRESS_DNS); + MQTT_SERVER = fram_ip_retrieve(FRAM_ADDRESS_MQTT_SERVER); + fram_hostname_retrieve(); + fram_mqtt_port_retrieve(); + fram_mqtt_useauth_retrieve(); + fram_mqtt_username_retrieve(); + fram_mqtt_password_retrieve(); mqtt.setServer(MQTT_SERVER, MQTT_PORT); - eeprom_basetopic_retrieve(); + fram_basetopic_retrieve(); base_topic_length = strlen(MQTT_BASE_TOPIC) + 1; memcpy(STATE_REQUEST_TOPIC, MQTT_BASE_TOPIC, 20); strcat(STATE_REQUEST_TOPIC, "/requeststate"); @@ -361,9 +361,9 @@ void eeprom_retrieve_init() 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(EEPROM_ADDRESS_ADC_REPORT_STATE, (uint8_t *)adc_report_enable, 8); - ESPMega_FRAM.read(EEPROM_ADDRESS_DAC_STATE, (uint8_t *)dac_states, 4); - ESPMega_FRAM.read(EEPROM_ADDRESS_DAC_VALUE, (uint8_t *)dac_values, 8); + 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]); @@ -463,9 +463,9 @@ void ota_begin() if(!value.compareTo("yes")) use_auth = true; } else if(!arg.compareTo("webui_username")) { - ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)value.c_str(), value.length()+1); + ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_USERNAME, (uint8_t *)value.c_str(), value.length()+1); } else if(!arg.compareTo("webui_password")) { - ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)value.c_str(), value.length()+1); + ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)value.c_str(), value.length()+1); } } set_mqtt_useauth(use_auth); @@ -748,7 +748,7 @@ void mqtt_callback(char *topic, byte *payload, unsigned int length) } /** - * @brief Initializes the threads for various tasks such as MQTT connection, environment reporting, EEPROM PWM update, and user timer tick. + * @brief Initializes the threads for various tasks such as MQTT connection, environment reporting, FRAM PWM update, and user timer tick. * */ void thread_initialization() @@ -761,8 +761,8 @@ void thread_initialization() environment_reporter.onRun(publish_env_state); environment_reporter.setInterval(5000); #endif - eeprom_pwm_updater.onRun(eeprom_pwm_update); - eeprom_pwm_updater.setInterval(1000); + fram_pwm_updater.onRun(fram_pwm_update); + fram_pwm_updater.setInterval(1000); user_timer_tick.onRun(timer_tick_callback); user_timer_tick.setInterval(15000); #ifdef ENABLE_ANALOG_MODULE @@ -1559,34 +1559,34 @@ void trigger15() #endif // End Internal LCD Code Block /** - * @brief Updates the PWM states and values in EEPROM if they have changed. + * @brief Updates the PWM states and values in FRAM if they have changed. * - * If the current PWM states or values are different from the ones stored in EEPROM, - * this function updates the EEPROM with the current values. + * If the current PWM states or values are different from the ones stored in FRAM, + * this function updates the FRAM with the current values. */ -void eeprom_pwm_update() +void fram_pwm_update() { - if (memcmp(pwm_states, pwm_states_eeprom, 16)) + if (memcmp(pwm_states, pwm_states_fram, 16)) { - memcpy(pwm_states_eeprom, pwm_states, 16); - ESPMega_FRAM.write(3, pwm_states_eeprom, 16); + memcpy(pwm_states_fram, pwm_states, 16); + ESPMega_FRAM.write(3, pwm_states_fram, 16); } - if (memcmp(pwm_values, pwm_values_eeprom, 32)) + if (memcmp(pwm_values, pwm_values_fram, 32)) { - memcpy(pwm_values_eeprom, pwm_values, 32); - ESPMega_FRAM.write(19, pwm_values_eeprom, 32); + memcpy(pwm_values_fram, pwm_values, 32); + ESPMega_FRAM.write(19, pwm_values_fram, 32); } } /** - * @brief Sets the IP address and updates it in EEPROM. + * @brief Sets the IP address and updates it in FRAM. * * @param address The IP address to set. */ void set_ip(String address) { IP.fromString(address); - eeprom_ip_update(EEPROM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]); + fram_ip_update(FRAM_ADDRESS_IP, IP[0], IP[1], IP[2], IP[3]); } /** @@ -1597,7 +1597,7 @@ void set_ip(String address) void set_netmask(String address) { SUBNET.fromString(address); - eeprom_ip_update(EEPROM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]); + fram_ip_update(FRAM_ADDRESS_SUBNET, SUBNET[0], SUBNET[1], SUBNET[2], SUBNET[3]); } /** @@ -1607,33 +1607,33 @@ void set_netmask(String address) void set_dns(String address) { DNS.fromString(address); - eeprom_ip_update(EEPROM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]); + fram_ip_update(FRAM_ADDRESS_DNS, DNS[0], DNS[1], DNS[2], DNS[3]); } /** - * @brief Sets the gateway IP address and updates the EEPROM. + * @brief Sets the gateway IP address and updates the FRAM. * * @param address The gateway IP address as a String. */ void set_gw(String address) { GATEWAY.fromString(address); - eeprom_ip_update(EEPROM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]); + fram_ip_update(FRAM_ADDRESS_GATEWAY, GATEWAY[0], GATEWAY[1], GATEWAY[2], GATEWAY[3]); } /** - * @brief Sets the MQTT server address and updates the EEPROM. + * @brief Sets the MQTT server address and updates the FRAM. * * @param address The MQTT server address as a String. */ void set_mqtt_server(String address) { MQTT_SERVER.fromString(address); - eeprom_ip_update(EEPROM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]); + fram_ip_update(FRAM_ADDRESS_MQTT_SERVER, MQTT_SERVER[0], MQTT_SERVER[1], MQTT_SERVER[2], MQTT_SERVER[3]); } /** - * @brief Updates the IP address in EEPROM at the specified ROM address. + * @brief Updates the IP address in FRAM at the specified ROM address. * * @param rom_address The ROM address where the IP address is stored. * @param byte1 The first byte of the IP address. @@ -1641,19 +1641,19 @@ void set_mqtt_server(String address) * @param byte3 The third byte of the IP address. * @param byte4 The fourth byte of the IP address. */ -void eeprom_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) +void fram_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) { uint8_t addressblock[4] = {byte1, byte2, byte3, byte4}; ESPMega_FRAM.write(rom_address, addressblock, 4); } /** - * @brief Retrieves an IP address from EEPROM memory. + * @brief Retrieves an IP address from FRAM memory. * - * @param rom_address The address in EEPROM memory where the IP address is stored. + * @param rom_address The address in FRAM memory where the IP address is stored. * @return The retrieved IP address. */ -IPAddress eeprom_ip_retrieve(uint16_t rom_address) +IPAddress fram_ip_retrieve(uint16_t rom_address) { uint8_t addressblock[4]; ESPMega_FRAM.read(rom_address, addressblock, 4); @@ -1668,40 +1668,40 @@ IPAddress eeprom_ip_retrieve(uint16_t rom_address) void set_hostname(String hostname) { hostname.toCharArray(HOSTNAME, 15); - ESPMega_FRAM.write(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); + ESPMega_FRAM.write(FRAM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } /** - * @brief Retrieves the hostname from EEPROM and stores it in the HOSTNAME variable. + * @brief Retrieves the hostname from FRAM and stores it in the HOSTNAME variable. * */ -void eeprom_hostname_retrieve() +void fram_hostname_retrieve() { - ESPMega_FRAM.read(EEPROM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); + ESPMega_FRAM.read(FRAM_ADDRESS_HOSTNAME, (uint8_t *)HOSTNAME, 15); } /** - * @brief Sets the base topic for MQTT communication and writes it to EEPROM. + * @brief Sets the base topic for MQTT communication and writes it to FRAM. * * @param topic The base topic to set. */ void set_basetopic(String topic) { topic.toCharArray(MQTT_BASE_TOPIC, 20); - ESPMega_FRAM.write(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); + ESPMega_FRAM.write(FRAM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } /** - * @brief Retrieves the MQTT base topic from EEPROM and stores it in MQTT_BASE_TOPIC array. + * @brief Retrieves the MQTT base topic from FRAM and stores it in MQTT_BASE_TOPIC array. * */ -void eeprom_basetopic_retrieve() +void fram_basetopic_retrieve() { - ESPMega_FRAM.read(EEPROM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); + ESPMega_FRAM.read(FRAM_ADDRESS_TOPIC, (uint8_t *)MQTT_BASE_TOPIC, 20); } /** - * @brief Sets the MQTT port in the EEPROM. + * @brief Sets the MQTT port in the FRAM. * * @param port The MQTT port to be set. */ @@ -1709,16 +1709,16 @@ void mqtt_port_set(uint16_t port) { uint8_t port_arr[2]; memcpy(port_arr, &port, 2); - ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); + ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_PORT, port_arr, 2); } /** - * @brief Retrieves the MQTT port from EEPROM and stores it in the MQTT_PORT variable. + * @brief Retrieves the MQTT port from FRAM and stores it in the MQTT_PORT variable. * */ -void eeprom_mqtt_port_retrieve() +void fram_mqtt_port_retrieve() { uint8_t port_arr[2]; - ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PORT, port_arr, 2); + ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_PORT, port_arr, 2); memcpy(&MQTT_PORT, port_arr, 2); } @@ -1786,67 +1786,67 @@ uint8_t ac_get_fan_speed() #endif /** - * @brief Retrieves the MQTT username from EEPROM and stores it in the MQTT_USERNAME global variable. + * @brief Retrieves the MQTT username from FRAM and stores it in the MQTT_USERNAME global variable. * */ -void eeprom_mqtt_username_retrieve() +void fram_mqtt_username_retrieve() { - ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32); + ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 32); } /** - * @brief Retrieves the MQTT password from EEPROM and stores it in the MQTT_PASSWORD global variable. + * @brief Retrieves the MQTT password from FRAM and stores it in the MQTT_PASSWORD global variable. * */ -void eeprom_mqtt_password_retrieve() +void fram_mqtt_password_retrieve() { - ESPMega_FRAM.read(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32); + ESPMega_FRAM.read(FRAM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 32); } /** - * @brief Sets the MQTT username and writes it to the EEPROM. + * @brief Sets the MQTT username and writes it to the FRAM. * * @param username The MQTT username to set. */ void set_mqtt_username(String username) { username.toCharArray(MQTT_USERNAME, 32); - ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20); + ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_USERNAME, (uint8_t *)MQTT_USERNAME, 20); } /** - * @brief Sets the MQTT password and writes it to the EEPROM. + * @brief Sets the MQTT password and writes it to the FRAM. * * @param password The MQTT password to set. */ void set_mqtt_password(String password) { password.toCharArray(MQTT_PASSWORD, 32); - ESPMega_FRAM.write(EEPROM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20); + ESPMega_FRAM.write(FRAM_ADDRESS_MQTT_PASSWORD, (uint8_t *)MQTT_PASSWORD, 20); } -void eeprom_mqtt_useauth_retrieve() +void fram_mqtt_useauth_retrieve() { - MQTT_USE_AUTH = ESPMega_FRAM.read8(EEPROM_ADDRESS_MQTT_USEAUTH); + MQTT_USE_AUTH = ESPMega_FRAM.read8(FRAM_ADDRESS_MQTT_USEAUTH); } /** - * @brief Sets the MQTT_USE_AUTH flag and writes it to the EEPROM. + * @brief Sets the MQTT_USE_AUTH flag and writes it to the FRAM. * * @param use_auth A boolean value indicating whether to use authentication for MQTT. */ void set_mqtt_useauth(bool use_auth) { MQTT_USE_AUTH = use_auth; - ESPMega_FRAM.write8(EEPROM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH); + ESPMega_FRAM.write8(FRAM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH); } void set_webui_username(String username) { username.toCharArray(WEBUI_USERNAME, 32); - ESPMega_FRAM.write(EEPROM_ADDRESS_WEBUI_USERNAME, (uint8_t *)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(EEPROM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); + ESPMega_FRAM.write(FRAM_ADDRESS_WEBUI_PASSWORD, (uint8_t *)WEBUI_PASSWORD, 32); } /** @@ -1920,20 +1920,20 @@ void check_boot_reset() void enable_adc(int id) { adc_report_enable[id] = true; - ESPMega_FRAM.write8(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 1); + 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 EEPROM. + * 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(EEPROM_ADDRESS_ADC_REPORT_STATE + id, 0); + ESPMega_FRAM.write8(FRAM_ADDRESS_ADC_REPORT_STATE + id, 0); publish_adc_state(id); } @@ -2122,7 +2122,7 @@ void dac_set_value(int id, int value) { dac_values[id] = value; ESPMega_dacWrite(id, dac_values[id] * dac_states[id]); - ESPMega_FRAM.write16(EEPROM_ADDRESS_DAC_VALUE + id * 2, dac_values[id]); + ESPMega_FRAM.write16(FRAM_ADDRESS_DAC_VALUE + id * 2, dac_values[id]); publish_dac_value(id); } @@ -2130,7 +2130,7 @@ void dac_set_value(int id, int value) * @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 EEPROM for persistence across power cycles. + * 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. @@ -2139,7 +2139,7 @@ void dac_set_state(int id, bool state) { dac_states[id] = state; ESPMega_dacWrite(id, dac_values[id] * dac_states[id]); - ESPMega_FRAM.write8(EEPROM_ADDRESS_DAC_STATE + id, dac_states[id]); + ESPMega_FRAM.write8(FRAM_ADDRESS_DAC_STATE + id, dac_states[id]); publish_dac_state(id); } diff --git a/src/espmega_iot_core.hpp b/src/espmega_iot_core.hpp index bf277ec..f7cd015 100644 --- a/src/espmega_iot_core.hpp +++ b/src/espmega_iot_core.hpp @@ -105,8 +105,8 @@ void trigger13(); void trigger14(); void trigger15(); -void eeprom_retrieve_init(); -void eeprom_pwm_update(); +void fram_retrieve_init(); +void fram_pwm_update(); void lcd_ac_refresh_fan(); void lcd_ac_refresh_mode(); @@ -116,19 +116,19 @@ void set_netmask(String address); void set_dns(String address); void set_gw(String address); void set_mqtt_server(String address); -void eeprom_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4); -IPAddress eeprom_ip_retrieve(uint16_t rom_address); +void fram_ip_update(uint16_t rom_address, uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4); +IPAddress fram_ip_retrieve(uint16_t rom_address); void set_hostname(String hostname); -void eeprom_hostname_retrieve(); +void fram_hostname_retrieve(); void set_basetopic(String topic); -void eeprom_basetopic_retrieve(); +void fram_basetopic_retrieve(); void mqtt_port_set(uint16_t port); -void eeprom_mqtt_port_retrieve(); -void eeprom_mqtt_username_retrieve(); -void eeprom_mqtt_password_retrieve(); +void fram_mqtt_port_retrieve(); +void fram_mqtt_username_retrieve(); +void fram_mqtt_password_retrieve(); void set_mqtt_username(String username); void set_mqtt_password(String password); -void eeprom_mqtt_useauth_retrieve(); +void fram_mqtt_useauth_retrieve(); void set_mqtt_useauth(bool use_auth); void factory_reset(); From 921a5f1cc45fd2109cd5433e4d82642d16e63413 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Mon, 4 Dec 2023 23:03:52 +0700 Subject: [PATCH 25/25] automated builds --- .gitignore | 4 +- .vscode/settings.json | 3 +- gen_release.py | 66 +++++++++++++++++ platformio.ini | 151 ++++++++++++++++++++++++++++++++++++++- src/espmega_iot_core.cpp | 4 ++ src/user_code.hpp | 11 +-- 6 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 gen_release.py diff --git a/.gitignore b/.gitignore index 5c228a4..a4a37ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ .vscode/ipch .vs/ .vscode/ -.vscode/settings.json \ No newline at end of file +.vscode/settings.json +firmware/ +release/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 2975662..ee32b37 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -73,5 +73,6 @@ "C_Cpp_Runner.useLeakSanitizer": false, "C_Cpp_Runner.showCompilationTime": false, "C_Cpp_Runner.useLinkTimeOptimization": false, - "C_Cpp_Runner.msvcSecureNoWarnings": false + "C_Cpp_Runner.msvcSecureNoWarnings": false, + "cmake.sourceDirectory": "D:/Git/iot-firmware/.pio/libdeps/full/Adafruit BusIO" } \ No newline at end of file diff --git a/gen_release.py b/gen_release.py new file mode 100644 index 0000000..ed453a7 --- /dev/null +++ b/gen_release.py @@ -0,0 +1,66 @@ +import os +import shutil +import subprocess +import sys +import platform +import subprocess +import os +import shutil +import subprocess +import sys +import platform + + +# 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') + +# Define the path to the release folder +release_folder = os.path.join(current_dir, 'release') + +# Add the path to the PlatformIO executable to the system PATH +platformio_path = os.path.expanduser('~/.platformio/penv/Scripts') + +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() + +# Build the PlatformIO project +if len(sys.argv) > 1: + # If arguments are supplied, build the environments that match the arguments + environments = sys.argv[1:] + for environment in environments: + subprocess.run([f'{platformio_path}/platformio.exe', 'run', '-e', environment], 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 appended + new_file_name = os.path.join(release_folder, f"{subfolder}_{git_branch}.bin") + shutil.move(firmware_file, new_file_name) +else: + # If no argument is supplied, build all environments + subprocess.run([f'{platformio_path}/platformio.exe', 'run'], 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 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 appended + new_file_name = os.path.join(release_folder, f"{subfolder}_{git_branch}.bin") + shutil.move(firmware_file, new_file_name) diff --git a/platformio.ini b/platformio.ini index 1995297..b32f365 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,7 +8,153 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:wt32-eth01] +[platformio] +build_dir = .\firmware + +[env:full] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_INTERNAL_LCD -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE -DENABLE_ANALOG_MODULE -DENABLE_WEBUI +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:lcd_climate] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_INTERNAL_LCD -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:webui] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_WEBUI +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 + +[env:climate_webui] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE -DENABLE_WEBUI +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:lcd_webui] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_INTERNAL_LCD -DENABLE_WEBUI +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:ir_climate_analog_webui] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_IR_MODULE -DENABLE_CLIMATE_MODULE -DENABLE_ANALOG_MODULE -DENABLE_WEBUI +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:lcd_analog] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_INTERNAL_LCD -DENABLE_ANALOG_MODULE +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:lcd] +platform = espressif32 +board = wt32-eth01 +framework = arduino +board_build.f_cpu = 240000000L +build_flags = -DENABLE_INTERNAL_LCD +lib_deps = siwats/ESPMegaPROR3@^1.3.0 + knolleary/PubSubClient@^2.8 + ivanseidel/ArduinoThread@^2.1.1 + arduino-libraries/Arduino_BuiltIn@^1.0.0 + dersimn/PubSubClientTools@^0.6 + z3t0/IRremote@^4.2.0 + robtillaart/DHTNEW@^0.4.18 + seithan/Easy Nextion Library@^1.0.6 + robtillaart/FRAM_I2C@^0.6.1 + esphome/ESPAsyncWebServer-esphome@^3.1.0 +monitor_speed = 115200 + +[env:minimal] platform = espressif32 board = wt32-eth01 framework = arduino @@ -22,5 +168,4 @@ lib_deps = siwats/ESPMegaPROR3@^1.3.0 robtillaart/DHTNEW@^0.4.18 seithan/Easy Nextion Library@^1.0.6 robtillaart/FRAM_I2C@^0.6.1 - esphome/ESPAsyncWebServer-esphome@^3.1.0 -monitor_speed = 115200 \ No newline at end of file + esphome/ESPAsyncWebServer-esphome@^3.1.0 \ No newline at end of file diff --git a/src/espmega_iot_core.cpp b/src/espmega_iot_core.cpp index ddfcaf2..a20b559 100644 --- a/src/espmega_iot_core.cpp +++ b/src/espmega_iot_core.cpp @@ -1837,6 +1837,7 @@ void set_mqtt_useauth(bool use_auth) ESPMega_FRAM.write8(FRAM_ADDRESS_MQTT_USEAUTH, MQTT_USE_AUTH); } +#ifdef ENABLE_WEBUI void set_webui_username(String username) { username.toCharArray(WEBUI_USERNAME, 32); @@ -1848,6 +1849,7 @@ 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. @@ -1884,8 +1886,10 @@ 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 diff --git a/src/user_code.hpp b/src/user_code.hpp index fba970a..938316e 100644 --- a/src/user_code.hpp +++ b/src/user_code.hpp @@ -16,11 +16,12 @@ #define VIRTUAL_INTERRUPT_PRELOAD // Preload Virtual Interrupts buffer // Enable Software Module(s) -#define ENABLE_INTERNAL_LCD -#define ENABLE_IR_MODULE -#define ENABLE_CLIMATE_MODULE // Require IR Module -#define ENABLE_ANALOG_MODULE -#define ENABLE_WEBUI +// Deprecated. Use Build Flags instead. +// #define ENABLE_INTERNAL_LCD +// #define ENABLE_IR_MODULE +// #define ENABLE_CLIMATE_MODULE // Require IR Module +// #define ENABLE_ANALOG_MODULE +// #define ENABLE_WEBUI // IR Kit Configuration #define IR_RECIEVE_PIN 35