Skip to content

Commit

Permalink
Add MQTT support
Browse files Browse the repository at this point in the history
  • Loading branch information
DrA1ex committed Sep 6, 2024
1 parent e506630 commit 49a163a
Show file tree
Hide file tree
Showing 17 changed files with 615 additions and 62 deletions.
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lib_deps = fastled/FastLED@^3.6.0
me-no-dev/ESPAsyncTCP@^1.2.2
#me-no-dev/ESP Async WebServer@^1.2.4 TODO: doesn't work well
https://github.com/yubox-node-org/ESPAsyncWebServer.git
marvinroger/AsyncMqttClient@^0.9.0
arduino-libraries/NTPClient@^3.2.1
bblanchon/ArduinoJson@^7.1.0

Expand Down
46 changes: 45 additions & 1 deletion src/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,20 @@ Application::Application(Storage<Config> &config_storage, Storage<PresetNames> &
config(config_storage.get()), preset_names(preset_names_storage.get()),
preset_configs(preset_configs_storage.get()), custom_palette_config(custom_palette_storage.get()),
night_mode_manager(night_mode_manager),
wave_provider(wave_provider), spectrum_provider(spectrum_provider), parametric_provider(parametric_provider) {}
wave_provider(wave_provider), spectrum_provider(spectrum_provider), parametric_provider(parametric_provider) {

event_property_changed.subscribe(this, [this](auto sender, auto type, auto arg) {
if (sender == this) return;

if (type == NotificationProperty::COLOR) {
this->change_color(*(uint32_t *) arg);
} else if (type == NotificationProperty::NIGHT_MODE_ENABLED) {
this->night_mode_manager.reset();
}

this->load();
});
}

void Application::load() {
const auto &preset = this->preset();
Expand Down Expand Up @@ -135,6 +148,37 @@ void Application::brightness_decrease() {
D_PRINT("Decrease brightness");
}

void Application::change_color(uint32_t color) {
auto preset_index = preset_configs.count - 1;
auto &preset = preset_configs.presets[preset_index];

auto preset_name = "API Color";
memcpy(preset_names.names[preset_index], preset_name, std::min<uint8_t>(preset_names.length, strlen(preset_name)));

preset.color_effect = ColorEffectEnum::SOLID;
config.preset_id = preset_index;

auto hsv = rgb2hsv_approximate(color);
preset.speed = hsv.hue;
preset.scale = hsv.sat;

load();
}

uint32_t Application::current_color() {
auto preset_index = preset_configs.count - 1;
auto &preset = preset_configs.presets[preset_index];

if (preset.color_effect == ColorEffectEnum::SOLID) {
CRGB color{};
hsv2rgb_rainbow(CHSV(preset.speed, preset.scale, 255), color);

return static_cast<uint32_t>(color) & 0xffffff;
}

return 0xffffff;
}

SignalProvider *Application::signal_provider() const {
if (config.audio_config.is_spectrum()) {
return spectrum_provider;
Expand Down
9 changes: 8 additions & 1 deletion src/application.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include "config.h"
#include "metadata.h"
#include "misc/storage.h"
#include "misc/event_topic.h"
#include "night_mode.h"

class Application {
Expand Down Expand Up @@ -29,6 +31,8 @@ class Application {

CRGBPalette16 current_palette = CRGBPalette16();

EventTopic<NotificationProperty> event_property_changed;

Application(Storage<Config> &config_storage, Storage<PresetNames> &preset_names_storage,
Storage<PresetConfigs> &preset_configs_storage, Storage<CustomPaletteConfig> &custom_palette_storage,
NightModeManager &night_mode_manager,
Expand All @@ -44,10 +48,13 @@ class Application {
void brightness_increase();
void brightness_decrease();

void change_color(uint32_t color);
uint32_t current_color();

void restart();

inline PresetConfig &preset() { return preset_configs.presets[config.preset_id]; }
[[nodiscard]] BrightnessSettings get_brightness_settings() const;

SignalProvider* signal_provider() const;
SignalProvider *signal_provider() const;
};
2 changes: 1 addition & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class NtpTime;

enum class AppState {
enum class AppState: uint8_t {
INITIALIZATION,
NORMAL,
CALIBRATION,
Expand Down
18 changes: 18 additions & 0 deletions src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,21 @@
#define AUDIO_GAIN (1u)
#define AUDIO_GATE (1u)
#define AUDIO_WINDOW_DURATION (5000u)


#define MQTT (0u) // MQTT protocol Enabled

#define MQTT_CONNECTION_TIMEOUT (15000u) // Connection attempt timeout to MQTT server
#define MQTT_RECONNECT_TIMEOUT (5000u) // Time before new reconnection attempt to MQTT server

#define MQTT_PREFIX MDNS_NAME
#define MQTT_TOPIC_BRIGHTNESS MQTT_PREFIX "/brightness"
#define MQTT_TOPIC_POWER MQTT_PREFIX "/power"
#define MQTT_TOPIC_COLOR MQTT_PREFIX "/color"
#define MQTT_TOPIC_NIGHT_MODE MQTT_PREFIX "/night_mode"

#define MQTT_OUT_PREFIX MQTT_PREFIX "/out"
#define MQTT_OUT_TOPIC_BRIGHTNESS MQTT_OUT_PREFIX "/brightness"
#define MQTT_OUT_TOPIC_POWER MQTT_OUT_PREFIX "/power"
#define MQTT_OUT_TOPIC_COLOR MQTT_OUT_PREFIX "/color"
#define MQTT_OUT_TOPIC_NIGHT_MODE MQTT_OUT_PREFIX "/night_mode"
5 changes: 5 additions & 0 deletions src/credentials.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@

#define CREDENTIAL_AUTH_USER "esp_lamp"
#define CREDENTIAL_AUTH_PASSWORD "password"

#define MQTT_HOST "example.com"
#define MQTT_PORT (1234u)
#define MQTT_USER "esp_user"
#define MQTT_PASSWORD "esp_pass"
24 changes: 22 additions & 2 deletions src/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,40 @@
#define __DEBUG_LEVEL_VERBOSE 0

#ifdef DEBUG
#include <ctime>

#define D_PRINT(x) Serial.println(x)
#define D_PRINTF(...) Serial.printf(__VA_ARGS__)
#define D_WRITE(x) Serial.print(x)

#define D_PRINT_HEX(ptr, length) \
D_WRITE("HEX: "); \
for (unsigned int i = 0; i < length; ++i) { \
D_PRINTF("%02X ", (ptr)[i]); \
} \
D_PRINT()

#define D_TIME_STRING(unix_time) ([](time_t time) { \
static char buffer[20]; \
struct tm* time_info; \
time_info = localtime(&time); \
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_info); \
return buffer; \
}(unix_time))

#if DEBUG_LEVEL == __DEBUG_LEVEL_VERBOSE
#define VERBOSE(ARG) ARG
#else
#define VERBOSE(ARG)
#endif

#else
#define D_PRINT(x)
#define D_PRINTF(...)
#define D_WRITE(x)
#define D_PRINT_HEX(ptr, length)

#define VERBOSE(ARG)
#endif
#endif

template<typename T>
const char *__debug_enum_str(T) { return "Unsupported"; }
5 changes: 5 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "network/wifi.h"
#include "network/web.h"
#include "network/protocol/server/api.h"
#include "network/protocol/server/mqtt.h"
#include "network/protocol/server/udp.h"
#include "network/protocol/server/ws.h"

Expand Down Expand Up @@ -82,6 +83,7 @@ WifiManager wifi_manager;
WebServer web_server(WEB_PORT);

ApiWebServer api_server(app);
MqttServer mqtt_server(app);
UdpServer udp_server(app);
WebSocketServer ws_server(app);

Expand Down Expand Up @@ -312,6 +314,7 @@ void service_loop(void *) {
udp_server.begin(UDP_PORT);
ws_server.begin(web_server);

if constexpr (MQTT) mqtt_server.begin();

web_server.on("/debug", HTTP_GET, [](AsyncWebServerRequest *request) {
char result[320] = {};
Expand Down Expand Up @@ -344,6 +347,8 @@ void service_loop(void *) {

udp_server.handle_incoming_data();
ws_server.handle_incoming_data();

if constexpr (MQTT) mqtt_server.handle_connection();
break;
}

Expand Down
71 changes: 71 additions & 0 deletions src/metadata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include "metadata.h"

#include <stddef.h>

#include "constants.h"

std::map<PacketType, PropertyMetadata> PacketTypeMetadataMap = {
{
PacketType::POWER_ON,
{
NotificationProperty::POWER, PacketType::POWER_ON,
offsetof(Config, power), sizeof(Config::power),
MQTT_TOPIC_POWER, MQTT_OUT_TOPIC_POWER,
}
},
{
PacketType::POWER_OFF,
{
NotificationProperty::POWER, PacketType::POWER_OFF,
offsetof(Config, power), sizeof(Config::power),
MQTT_TOPIC_POWER, MQTT_OUT_TOPIC_POWER,
}
},
{
PacketType::MAX_BRIGHTNESS,
{
NotificationProperty::BRIGHTNESS, PacketType::MAX_BRIGHTNESS,
offsetof(Config, max_brightness), sizeof(Config::max_brightness),
MQTT_TOPIC_BRIGHTNESS, MQTT_OUT_TOPIC_BRIGHTNESS,
}
},
{
PacketType::NIGHT_MODE_ENABLED,
{
NotificationProperty::NIGHT_MODE_ENABLED, PacketType::NIGHT_MODE_ENABLED,
offsetof(Config, night_mode.enabled), sizeof(Config::night_mode.enabled),
MQTT_TOPIC_NIGHT_MODE, MQTT_OUT_TOPIC_NIGHT_MODE,
}
},
};

std::map<NotificationProperty, std::vector<PropertyMetadata>> PropertyMetadataMap =
_build_property_metadata_map(PacketTypeMetadataMap);

std::map<String, PropertyMetadata> TopicPropertyMetadata =
_build_topic_property_metadata_map(PacketTypeMetadataMap);

std::map<NotificationProperty, std::vector<PropertyMetadata>> _build_property_metadata_map(
std::map<PacketType, PropertyMetadata> &packetMapping) {
std::map<NotificationProperty, std::vector<PropertyMetadata>> result;

for (auto &[packetType, metadata]: packetMapping) {
std::vector<PropertyMetadata> &prop = result[metadata.property];
prop.push_back(metadata);
}

return result;
}

std::map<String, PropertyMetadata> _build_topic_property_metadata_map(
std::map<PacketType, PropertyMetadata> &packetMapping) {
std::map<String, PropertyMetadata> result;

for (auto &[packetType, metadata]: packetMapping) {
if (metadata.mqtt_in_topic == nullptr) continue;

result[metadata.mqtt_in_topic] = metadata;
}

return result;
}
42 changes: 42 additions & 0 deletions src/metadata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <vector>
#include <map>

#include <Arduino.h>

#include "config.h"
#include "network/enum.h"
#include "utils/enum.h"

class Application;

MAKE_ENUM(NotificationProperty, uint8_t,
POWER, 0,
BRIGHTNESS, 1,
COLOR, 2,
NIGHT_MODE_ENABLED, 3,
)

struct PropertyMetadata {
NotificationProperty property;
PacketType packet_type;

uint8_t value_offset{};
uint8_t value_size{};

const char *mqtt_in_topic = nullptr;
const char *mqtt_out_topic = nullptr;
};

extern std::map<PacketType, PropertyMetadata> PacketTypeMetadataMap;
extern std::map<NotificationProperty, std::vector<PropertyMetadata>> PropertyMetadataMap;
extern std::map<String, PropertyMetadata> TopicPropertyMetadata;

std::map<NotificationProperty, std::vector<PropertyMetadata>> _build_property_metadata_map(
std::map<PacketType, PropertyMetadata> &packetMapping);

std::map<String, PropertyMetadata> _build_topic_property_metadata_map(
std::map<PacketType, PropertyMetadata> &packetMapping);
Loading

0 comments on commit 49a163a

Please sign in to comment.