init esp-idf project

This commit is contained in:
RaffaelW 2025-11-15 22:15:54 +01:00
parent b3468b4f01
commit a97872239e
21 changed files with 2362 additions and 959 deletions

61
.gitignore vendored Normal file → Executable file
View file

@ -1,5 +1,58 @@
# Development # .gitignore für ESP-IDF / CMake-Projekt
.pio # --- Build artefacts -----------------------------------------------------
.vscode /build/
!.vscode\extensions.json *.elf
*.bin
*.hex
*.map
*.img
# CMake / build system
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
compile_commands.json
# ESP-IDF specific
sdkconfig.old
flasher_args.json
flash_args*
flash_app_args
flash_bootloader_args
flash_project_args
bootloader-prefix/
project_description.json
managed_components/
# Component build directories
components/**/build/
partition_table/build/
# IDEs / editors / OS
.vscode/
.idea/
*.swp
*~
.DS_Store
# direnv (local environment/profile cache)
.direnv/
# Python / virtualenvs
__pycache__/
*.pyc
venv/
venv*/
.env
# Logs / temp
*.log
*.tmp
*.bak
# Misc
*.local
# Keep Snyk instructions file tracked (project policy)
# .github/instructions/snyk_rules.instructions.md

6
.gitmodules vendored
View file

@ -1,6 +0,0 @@
[submodule "lib/ArtNet"]
path = lib/ArtNet
url = https://github.com/psxde/ArtNet.git
[submodule "lib/AsyncWebServer_ESP32_W5500"]
path = lib/AsyncWebServer_ESP32_W5500
url = https://github.com/psxde/AsyncWebServer_ESP32_W5500.git

View file

@ -1,10 +0,0 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

6
CMakeLists.txt Normal file
View file

@ -0,0 +1,6 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(dmx-interface)

@ -1 +0,0 @@
Subproject commit 5d9c42b531404ccfbcb14106d6312b03a166868a

@ -1 +0,0 @@
Subproject commit 38de6ac248c7f270ca3b77ba38512ba39919aed8

2
main/CMakeLists.txt Normal file
View file

@ -0,0 +1,2 @@
idf_component_register(SRCS "dmx-interface.c"
INCLUDE_DIRS ".")

6
main/dmx-interface.c Normal file
View file

@ -0,0 +1,6 @@
#include <stdio.h>
void app_main(void)
{
}

5
partitions.csv Executable file
View file

@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, littlefs, , 0xF0000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x6000
3 phy_init data phy 0xf000 0x1000
4 factory app factory 0x10000 1M
5 storage data littlefs 0xF0000

View file

@ -1,29 +0,0 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = lolin_s2_mini
[env]
framework = arduino
board_build.filesystem = littlefs
[env:lolin_s2_mini]
platform = espressif32
board = lolin_s2_mini
lib_deps =
bblanchon/ArduinoJson @ ^7.2.0
someweisguy/esp_dmx
extra_scripts = pre:pre_extra_script.py
[env:esp32_wroom_32]
platform = espressif32
board = nodemcu-32s
lib_deps = bblanchon/ArduinoJson @ ^7.2.0

View file

@ -1,8 +0,0 @@
Import("env")
if env.IsIntegrationDump():
# stop the current script execution
Return()
env.Execute("git submodule update --init --recursive")
print("✅ SUBMODULES UPDATED")

2286
sdkconfig Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,515 +0,0 @@
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
// #include <USB.h>
// #include "USBCDC.h"
#include "driver/temp_sensor.h"
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
#include <AsyncWebServer_ESP32_W5500.h>
// #include "w5500/esp32_w5500.h"
// #include <ESPAsyncWebServer.h>
#include <ArtnetWiFi.h>
#include <ArduinoJson.h>
// #include "ESPDMX.h"
#include <Arduino.h>
#include <esp_dmx.h>
#include <LittleFS.h>
#include "websocket.h"
#include "routes/config.h"
#include "routes/networks.h"
#include "routes/status.h"
dmx_port_t dmx1 = DMX_NUM_0; // for esp32s2
dmx_port_t dmx2 = DMX_NUM_1;
byte dmx1_data[DMX_PACKET_SIZE];
byte dmx2_data[DMX_PACKET_SIZE];
// Button
#define PIN_LED 7
#define PIN_BUTTON 5
uint8_t brightness_led = 20;
bool led_on = true;
double lastMills = 0;
// Ethernet stuff
#define ETH_SCK 36
#define ETH_SS 34
#define ETH_MOSI 35
#define ETH_MISO 37
#define ETH_INT 38
#define ETH_SPI_CLOCK_MHZ 25
byte mac[6];
AsyncWebServer server(80);
ArtnetWiFi artnet;
String broadcastIp;
uint8_t universe1;
uint8_t universe2;
Direction direction1;
Direction direction2;
enum class Status
{
Starting,
Resetting,
Normal,
Warning,
Critical
};
Status status;
struct BlinkingConfig
{
int interval_ms;
bool is_blinking;
int brightness;
};
BlinkingConfig getBlinkingConfig(Status status)
{
switch (status)
{
case Status::Starting:
return {500, true, brightness_led};
case Status::Resetting:
return {100, true, brightness_led};
case Status::Normal:
return {1000, false, brightness_led};
case Status::Warning:
return {500, true, 255};
case Status::Critical:
return {100, true, 255};
default:
return {1000, false, 0};
}
}
BlinkingConfig led_config = getBlinkingConfig(status);
void updateTimer(int interval_ms)
{
// TODO: update the tickspeed of the timer
}
void updateLed() // TODO: callback for timer
{
if (millis() - lastMills >= led_config.interval_ms)
{
lastMills = millis();
led_config = getBlinkingConfig(status);
if (led_config.is_blinking)
{
led_on = !led_on;
analogWrite(PIN_LED, led_on ? led_config.brightness : 0);
}
else
{
analogWrite(PIN_LED, led_config.brightness);
return;
}
}
}
void setStatus(Status newStatus)
{
status = newStatus;
led_config = getBlinkingConfig(status);
updateTimer(led_config.interval_ms);
updateLed();
}
void onButtonPress()
{
config.begin("dmx", true);
ButtonAction action = static_cast<ButtonAction>(config.getUInt("button-action", DEFAULT_BUTTON_ACTION));
config.end();
switch (action)
{
case ResetConfig:
config.begin("dmx", false);
config.clear();
config.end();
ESP.restart();
break;
case Restart:
config.begin("dmx", false);
config.putBool("restart-via-btn", true);
config.end();
ESP.restart();
break;
case None:
// do nothing
break;
}
}
void setup()
{
setStatus(Status::Starting);
pinMode(PIN_LED, OUTPUT);
updateLed();
Serial.begin(9600);
// Get ETH mac
delay(1000);
esp_efuse_mac_get_default(mac);
esp_read_mac(mac, ESP_MAC_ETH);
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x ESP MAC ETH\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP);
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x ESP MAC SOFTAP\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
esp_read_mac(mac, ESP_MAC_WIFI_STA); // ESP_MAC_BASE
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x ESP MAC BASE\n",
mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
// LED
config.begin("dmx", true);
brightness_led = config.getUInt("led-brightness", DEFAULT_LED_BRIGHTNESS);
bool restartViaButton = config.getBool("restart-via-btn", false);
config.end();
updateLed();
// Button
pinMode(PIN_BUTTON, INPUT_PULLUP);
if (digitalRead(PIN_BUTTON) == LOW && !restartViaButton)
{
setStatus(Status::Resetting);
unsigned long startTime = millis();
while (digitalRead(PIN_BUTTON) == LOW && (millis() - startTime <= 3000))
{
updateLed();
}
if (digitalRead(PIN_BUTTON) == LOW)
{
Serial.println("Reset config");
config.begin("dmx", false);
config.clear();
config.end();
setStatus(Status::Normal);
unsigned long startTime = millis();
while (millis() - startTime <= 2000)
{
updateLed();
}
}
}
config.begin("dmx", false);
config.putBool("restart-via-btn", false);
config.end();
setStatus(Status::Starting);
attachInterrupt(PIN_BUTTON, onButtonPress, FALLING);
// wait for serial monitor
unsigned long startTime = millis();
while (millis() - startTime <= 5000)
{
updateLed();
}
Serial.println("Starting DMX-Interface...");
config.begin("dmx", true);
universe1 = config.getUInt("universe-1", DEFAULT_UNIVERSE1);
universe2 = config.getUInt("universe-2", DEFAULT_UNIVERSE2);
direction1 = static_cast<Direction>(config.getUInt("direction-1", DEFAULT_DIRECTION1));
direction2 = static_cast<Direction>(config.getUInt("direction-2", DEFAULT_DIRECTION2));
Serial.printf("Port A: Universe %d %s\n", universe1, (direction1 == Input) ? "DMX -> Art-Net" : "Art-Net -> DMX");
Serial.printf("Port B: Universe %d %s\n", universe2, (direction2 == Input) ? "DMX -> Art-Net" : "Art-Net -> DMX");
Connection connection = static_cast<Connection>(config.getUInt("connection", DEFAULT_CONNECTION));
IpMethod ipMethod = static_cast<IpMethod>(config.getUInt("ip-method"), DEFAULT_IP_METHOD);
char hostname[30];
snprintf(hostname, sizeof(hostname), "ChaosDMX-%02X%02X", mac[4], mac[5]);
DEFAULT_SSID = hostname;
Serial.print("Hostname: ");
Serial.println(hostname);
String ssid = config.getString("ssid", DEFAULT_SSID);
String pwd = config.getString("password", DEFAULT_PASSWORD);
// Default IP as defined in standard https://art-net.org.uk/downloads/art-net.pdf, page 13
IPAddress ip = config.getUInt("ip", DEFAULT_IP);
IPAddress subnet = config.getUInt("subnet", DEFAULT_SUBNET);
IPAddress gateway = config.getUInt("gateway", 0);
config.end();
switch (connection)
{
case WiFiSta:
Serial.println("Initialize as WiFi Station");
WiFi.setHostname(hostname);
WiFi.begin(ssid, pwd);
Serial.println("SSID: " + ssid + ", pwd: " + pwd);
if (ipMethod == Static)
{
WiFi.config(ip, gateway, subnet);
Serial.println("IP: " + ip.toString() + ", gateway: " + gateway + ", subnet: " + subnet);
}
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
broadcastIp = String(WiFi.broadcastIP().toString().c_str());
Serial.println("");
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
Serial.print("MAC address: ");
Serial.println(WiFi.macAddress());
Serial.print("Broadcast IP: ");
Serial.println(broadcastIp);
break;
case Ethernet:
{
Serial.println("Initialize as ETH");
ESP32_W5500_onEvent();
if (ETH.begin(ETH_MISO, ETH_MOSI, ETH_SCK, ETH_SS, ETH_INT, ETH_SPI_CLOCK_MHZ, SPI2_HOST, mac))
{ // Dynamic IP setup
}
else
{
Serial.println("Failed to configure Ethernet");
}
ETH.setHostname(hostname);
// ESP32_W5500_waitForConnect();
uint8_t timeout = 5; // in s
Serial.print("Wait for connect");
while (!ESP32_W5500_eth_connected && timeout > 0)
{
delay(1000);
timeout--;
Serial.print(".");
}
Serial.println();
if (ESP32_W5500_eth_connected)
{
Serial.println("DHCP OK!");
}
else
{
Serial.println("Set static IP");
ETH.config(ip, gateway, subnet);
}
broadcastIp = ETH.broadcastIP().toString();
Serial.print("Local IP : ");
Serial.println(ETH.localIP());
Serial.print("Subnet Mask : ");
Serial.println(ETH.subnetMask());
Serial.print("Gateway IP : ");
Serial.println(ETH.gatewayIP());
Serial.print("DNS Server : ");
Serial.println(ETH.dnsIP());
Serial.print("MAC address : ");
Serial.println(ETH.macAddress());
Serial.print("Broadcast IP: ");
Serial.println(broadcastIp);
Serial.println("Ethernet Successfully Initialized");
break;
}
default:
Serial.println("Initialize as WiFi AccessPoint");
WiFi.softAPsetHostname(hostname);
WiFi.softAP(ssid, pwd);
// AP always with DHCP
// WiFi.softAPConfig(ip, gateway, subnet);
broadcastIp = WiFi.softAPBroadcastIP().toString();
Serial.print("WiFi AP enabled, IP = ");
Serial.println(WiFi.softAPIP());
Serial.print("MAC address: ");
Serial.println(WiFi.softAPmacAddress());
Serial.print("Broadcast IP: ");
Serial.println(broadcastIp);
break;
}
// Initialize DMX ports
Serial.println("Initialize DMX...");
#ifdef CONFIG_IDF_TARGET_ESP32S2
dmx_config_t dmx_config = DMX_CONFIG_DEFAULT;
dmx_personality_t personalities[] = {};
int personality_count = 0;
dmx_driver_install(dmx1, &dmx_config, personalities, personality_count);
dmx_set_pin(dmx1, 21, 33, -1);
dmx_driver_install(dmx2, &dmx_config, personalities, personality_count);
dmx_set_pin(dmx2, 17, 18, -1);
Serial.printf("DMX driver 1 installed: %d\n", dmx_driver_is_installed(dmx1));
Serial.printf("DMX driver 2 installed: %d\n", dmx_driver_is_installed(dmx2));
Serial.printf("DMX driver 1 enabled: %d\n", dmx_driver_is_enabled(dmx1));
Serial.printf("DMX driver 2 enabled: %d\n", dmx_driver_is_enabled(dmx2));
#else
dmx1.init(21, 33, Serial1);
dmx2.init(17, 18, Serial2);
#endif
// Initialize Art-Net
Serial.println("Initialize Art-Net...");
artnet.begin();
// if Artnet packet comes to this universe, this function is called
if (direction1 == Output)
{
artnet.subscribeArtDmxUniverse(universe1, [&](const uint8_t *data, uint16_t size, const ArtDmxMetadata &metadata, const ArtNetRemoteInfo &remote)
{
dmx_write_offset(dmx1, 1, data, size);
dmx_send(dmx1);
dmx_wait_sent(dmx1, DMX_TIMEOUT_TICK); });
}
if (direction2 == Output)
{
artnet.subscribeArtDmxUniverse(universe2, [&](const uint8_t *data, uint16_t size, const ArtDmxMetadata &metadata, const ArtNetRemoteInfo &remote)
{
dmx_write_offset(dmx2, 1, data, size);
dmx_send(dmx2);
dmx_wait_sent(dmx2, DMX_TIMEOUT_TICK); });
}
if (!LittleFS.begin(true))
{
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request)
{ onGetConfig(request); });
server.on("/config", HTTP_DELETE, [](AsyncWebServerRequest *request)
{
config.begin("dmx", false);
config.clear();
config.end();
// respond with default config
onGetConfig(request);
ESP.restart(); });
server.on("/networks", HTTP_GET, [](AsyncWebServerRequest *request)
{ onGetNetworks(request); });
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
{
if (request->url() == "/config" && request->method() == HTTP_PUT) {
onPutConfig(request, data, len, index, total);
Serial.println("restarting ESP...");
ESP.restart();
} });
initWebSocket(&server);
server.begin();
Serial.println("Server started!");
// scan networks and cache them
WiFi.scanNetworks(true);
setStatus(Status::Normal);
// Internal temperature RP2040
/*float tempC = analogReadTemp(); // Get internal temperature
Serial.print("Temperature Celsius (ºC): ");
Serial.println(tempC);*/
// Internal temperature ESP32 https://www.espboards.dev/blog/esp32-inbuilt-temperature-sensor/
Serial.print("Temperature: ");
float result = 0;
temp_sensor_read_celsius(&result);
Serial.print(result);
Serial.println(" °C");
Serial.printf("Internal Total heap %d, internal Free Heap %d\n", ESP.getHeapSize(), ESP.getFreeHeap());
Serial.printf("SPIRam Total heap %d, SPIRam Free Heap %d\n", ESP.getPsramSize(), ESP.getFreePsram());
Serial.printf("ChipRevision %d, Cpu Freq %d, SDK Version %s\n", ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
Serial.printf("Flash Size %d, Flash Speed %d\n", ESP.getFlashChipSize(), ESP.getFlashChipSpeed());
}
void transmitDmxToArtnet(dmx_port_t dmxPort, byte *dmx_data, uint8_t artnetUniverse)
{
/* We need a place to store information about the DMX packets we receive. We
will use a dmx_packet_t to store that packet information. */
dmx_packet_t dmx_packet;
// check if there's a new DMX packet
if (dmx_receive(dmxPort, &dmx_packet, 0))
{
/* We should check to make sure that there weren't any DMX errors. */
if (!dmx_packet.err)
{
/* Don't forget we need to actually read the DMX data into our buffer so
that we can print it out. */
dmx_read_offset(dmxPort, 1, dmx_data, dmx_packet.size);
artnet.sendArtDmx(broadcastIp, artnetUniverse, dmx_data, dmx_packet.size);
}
else
{
/* Oops! A DMX error occurred! Don't worry, this can happen when you first
connect or disconnect your DMX devices. If you are consistently getting
DMX errors, then something may have gone wrong with your code or
something is seriously wrong with your DMX transmitter. */
Serial.printf("A DMX error occurred on port %d.\n", dmxPort);
}
}
}
void loop()
{
// only check for artnet packets if we expect to receive data
if (direction1 == Output || direction2 == Output)
{
// check if artnet packet has come and execute callback
artnet.parse();
}
if (direction1 == Input)
{
transmitDmxToArtnet(dmx1, dmx1_data, universe1);
}
if (direction2 == Input)
{
transmitDmxToArtnet(dmx2, dmx2_data, universe2);
}
webSocketLoop();
updateLed();
}

View file

@ -1,177 +0,0 @@
#include "config.h"
#include <stdexcept>
#include <ArduinoJson.h>
#include "WiFi.h"
Preferences config;
String DEFAULT_SSID = "";
#pragma region Utility
uint32_t parseIp(String str)
{
const int size = 4;
String ipStrings[size];
uint8_t ipIndex = 0;
for (int i = 0; i < str.length(); i++)
{
if (str[i] == '.')
{
ipIndex++;
continue;
}
ipStrings[ipIndex] += str[i];
}
String ip = "";
for (int i = 0; i < size; i++)
{
String paddedString = ipStrings[i];
while (paddedString.length() < 3)
{
paddedString = "0" + paddedString;
}
ip.concat(paddedString);
}
Serial.println("ip string: " + ip);
return atoi(ip.c_str());
}
IpMethod parseIpMethod(uint8_t ipMethod)
{
if (ipMethod > 0 || ipMethod < IP_METHOD_SIZE)
{
return static_cast<IpMethod>(ipMethod);
}
throw ::std::invalid_argument("Invalid IP method value" + ipMethod);
}
Connection parseConnection(uint8_t connection)
{
if (connection > 0 || connection < CONNECTION_SIZE)
{
return static_cast<Connection>(connection);
}
throw ::std::invalid_argument("Invalid connection value: " + connection);
}
Direction parseDirection(uint8_t direction)
{
if (direction > 0 || direction < DIRECTION_SIZE)
{
return static_cast<Direction>(direction);
}
throw ::std::invalid_argument("Invalid direction value: " + direction);
}
ButtonAction parseButtonAction(uint8_t buttonAction)
{
if (buttonAction > 0 || buttonAction < BUTTON_ACTION_SIZE)
{
return static_cast<ButtonAction>(buttonAction);
}
throw ::std::invalid_argument("Invalid value for button action: " + buttonAction);
}
#pragma endregion
void onGetConfig(AsyncWebServerRequest *request)
{
config.begin("dmx", true);
IPAddress ip = config.getUInt("ip", DEFAULT_IP);
IPAddress subnet = config.getUInt("subnet", DEFAULT_SUBNET);
IPAddress gateway = config.getUInt("gateway", 0);
JsonDocument doc;
doc["connection"] = config.getUInt("connection", DEFAULT_CONNECTION);
doc["ssid"] = config.getString("ssid", DEFAULT_SSID);
doc["password"] = config.getString("password", DEFAULT_PASSWORD);
doc["ip-method"] = config.getUInt("ip-method", DEFAULT_IP_METHOD);
doc["ip"] = ip.toString();
doc["subnet"] = subnet.toString();
doc["gateway"] = gateway != 0 ? gateway.toString() : "";
doc["universe-1"] = config.getUInt("universe-1", DEFAULT_UNIVERSE1);
doc["direction-1"] = config.getUInt("direction-1", DEFAULT_DIRECTION1);
doc["universe-2"] = config.getUInt("universe-2", DEFAULT_UNIVERSE2);
doc["direction-2"] = config.getUInt("direction-2", DEFAULT_DIRECTION2);
doc["led-brightness"] = config.getUInt("led-brightness", DEFAULT_LED_BRIGHTNESS);
doc["button-action"] = config.getUInt("button-action", DEFAULT_BUTTON_ACTION);
config.end();
String jsonString;
serializeJson(doc, jsonString);
request->send(200, "application/json", jsonString);
}
void onPutConfig(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
{
Serial.printf("[REQUEST]\t%s\r\n", (const char *)data);
JsonDocument doc;
deserializeJson(doc, data);
try
{
config.begin("dmx", false);
IpMethod ipMethod = parseIpMethod(doc["ip-method"].as<uint8_t>());
config.putUInt("ip-method", ipMethod);
if (ipMethod == Static)
{
IPAddress ipAddress;
ipAddress.fromString(doc["ip"].as<String>());
config.putUInt("ip", ipAddress);
IPAddress subnet;
subnet.fromString(doc["subnet"].as<String>());
config.putUInt("subnet", subnet);
IPAddress gateway;
gateway.fromString(doc["gateway"].as<String>());
config.putUInt("gateway", gateway);
}
Connection connection = parseConnection(doc["connection"].as<uint8_t>());
config.putUInt("connection", connection);
if (connection == WiFiSta || connection == WiFiAP)
{
config.putString("ssid", doc["ssid"].as<String>());
config.putString("password", doc["password"].as<String>());
}
Direction direction1 = parseDirection(doc["direction-1"].as<uint8_t>());
config.putUInt("direction-1", direction1);
Direction direction2 = parseDirection(doc["direction-2"].as<uint8_t>());
config.putUInt("direction-2", direction2);
config.putUInt("universe-1", doc["universe-1"]);
config.putUInt("universe-2", doc["universe-2"]);
config.putUInt("led-brightness", doc["led-brightness"]);
ButtonAction buttonAction = parseButtonAction(doc["button-action"].as<uint8_t>());
config.putUInt("button-action", buttonAction);
config.end();
request->send(200);
}
catch (::std::invalid_argument &e)
{
config.end();
request->send(400, "text/plain", e.what());
}
}

View file

@ -1,59 +0,0 @@
#include <AsyncWebServer_ESP32_W5500.h>
#include <Preferences.h>
#ifndef CONFIG_h
#define CONFIG_h
extern Preferences config;
enum IpMethod
{
Static,
DHCP
};
const uint8_t IP_METHOD_SIZE = 2;
enum Connection
{
WiFiSta,
WiFiAP,
Ethernet
};
const uint8_t CONNECTION_SIZE = 3;
enum Direction
{
Output,
Input
};
const uint8_t DIRECTION_SIZE = 2;
enum ButtonAction
{
None,
ResetConfig,
Restart
};
const uint8_t BUTTON_ACTION_SIZE = 3;
const Connection DEFAULT_CONNECTION = WiFiAP;
const IpMethod DEFAULT_IP_METHOD = DHCP;
extern String DEFAULT_SSID; // initialized in setup because it depends on the mac address
const String DEFAULT_PASSWORD = "mbgmbgmbg";
const IPAddress DEFAULT_IP(192, 168, 4, 1);
const IPAddress DEFAULT_SUBNET(255, 255, 255, 0);
const IPAddress DEFAULT_GATEWAY(2, 0, 0, 1);
const Direction DEFAULT_DIRECTION1 = Output;
const Direction DEFAULT_DIRECTION2 = Input;
const uint8_t DEFAULT_UNIVERSE1 = 1;
const uint8_t DEFAULT_UNIVERSE2 = 2;
const uint8_t DEFAULT_LED_BRIGHTNESS = 25;
const ButtonAction DEFAULT_BUTTON_ACTION = Restart;
void onGetConfig(AsyncWebServerRequest *request);
void onPutConfig(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total);
#endif

View file

@ -1,29 +0,0 @@
#include "networks.h"
void onGetNetworks(AsyncWebServerRequest *request)
{
JsonDocument doc;
JsonArray array = doc.to<JsonArray>();
int numberOfNetworks = WiFi.scanComplete();
if (numberOfNetworks == WIFI_SCAN_FAILED)
{
WiFi.scanNetworks(true);
}
else if (numberOfNetworks)
{
for (int i = 0; i < numberOfNetworks; ++i)
{
array.add(WiFi.SSID(i));
}
WiFi.scanDelete();
if (WiFi.scanComplete() == WIFI_SCAN_FAILED)
{
WiFi.scanNetworks(true);
}
}
String jsonString;
serializeJson(doc, jsonString);
request->send(200, "application/json", jsonString);
}

View file

@ -1,9 +0,0 @@
#include <AsyncWebServer_ESP32_W5500.h>
#include <ArduinoJson.h>
#ifndef NETWORKS_H
#define NETWORKS_H
void onGetNetworks(AsyncWebServerRequest *request);
#endif

View file

@ -1,43 +0,0 @@
#include "status.h"
int getTemperature()
{
float tempC = -1.0f;
temp_sensor_read_celsius(&tempC);
return static_cast<int>(round(tempC));
}
int8_t getWiFiStrength()
{
try
{
return WiFi.RSSI();
}
catch (...)
{
return 0;
}
}
JsonDocument buildStatusJson()
{
JsonDocument doc;
doc["uptime"] = millis();
doc["chip"]["model"] = ESP.getChipModel();
doc["chip"]["mac"] = ESP.getEfuseMac();
doc["chip"]["revision"] = ESP.getChipRevision();
doc["chip"]["cpuFreqMHz"] = ESP.getCpuFreqMHz();
doc["chip"]["cycleCount"] = ESP.getCycleCount();
doc["chip"]["tempC"] = getTemperature();
doc["sdkVersion"] = ESP.getSdkVersion();
doc["sketch"]["size"] = ESP.getSketchSize();
doc["sketch"]["md5"] = ESP.getSketchMD5();
doc["heap"]["free"] = ESP.getFreeHeap();
doc["heap"]["total"] = ESP.getHeapSize();
doc["psram"]["free"] = ESP.getFreePsram();
doc["psram"]["total"] = ESP.getPsramSize();
doc["connection"]["signalStrength"] = getWiFiStrength();
return doc;
}

View file

@ -1,5 +0,0 @@
#include <AsyncWebServer_ESP32_W5500.h>
#include <ArduinoJson.h>
#include <driver/temp_sensor.h>
JsonDocument buildStatusJson();

View file

@ -1,52 +0,0 @@
#include "websocket.h"
AsyncWebSocket ws("/ws");
long webSocketLastUpdate = 0;
const int WS_UPDATE_INTERVAL = 10 * 1000; // 10 seconds
String buildStatusString()
{
JsonDocument doc;
doc["type"] = "status";
doc["data"] = buildStatusJson();
String jsonString = "";
serializeJson(doc, jsonString);
return jsonString;
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
switch (type)
{
case WS_EVT_CONNECT:
Serial.printf("[WS] Client %u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
// directly send status to client
ws.text(client->id(), buildStatusString());
break;
case WS_EVT_DISCONNECT:
Serial.printf("[WS] Client %u disconnected\n", client->id());
break;
case WS_EVT_DATA:
Serial.printf("[WS] Data received from client %u: %s\n", client->id(), (char *)data);
break;
default:
break;
}
}
void webSocketLoop()
{
if (millis() - webSocketLastUpdate > WS_UPDATE_INTERVAL)
{
ws.textAll(buildStatusString());
webSocketLastUpdate = millis();
}
}
void initWebSocket(AsyncWebServer *server)
{
ws.onEvent(onEvent);
server->addHandler(&ws);
}

View file

@ -1,11 +0,0 @@
#include <AsyncWebServer_ESP32_W5500.h>
#include "routes/status.h"
#ifndef WEBSOCKET_H
#define WEBSOCKET_H
void initWebSocket(AsyncWebServer *server);
void webSocketLoop();
#endif