robot code

This commit is contained in:
Siwat Sirichai 2023-11-15 16:55:43 +07:00
parent 0bb47ef128
commit b102b25f17
9 changed files with 590 additions and 2 deletions

View File

@ -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 <espmega_iot_core.hpp>
// 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);

View File

@ -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 <ESPMegaPRO.h>

View File

@ -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;

View File

@ -1,13 +1,54 @@
/**
* @brief Class for measuring current and power consumption using a current transformer and an ADC.
*
*/
#pragma once
#include <ESPMegaPRO.h>
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;

View File

@ -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");

View File

@ -0,0 +1,2 @@
#pragma once
#include <ESPMegaPRO.h>

View File

@ -1,6 +1,11 @@
#include <user_code.hpp>
#include <espmega_iot_lcd.hpp>
/**
* @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;

View File

@ -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))) {

View File

@ -1,12 +1,45 @@
#pragma once
#include <ESPMegaPRO.h>
/**
* @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;