added ota and more led strips
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -37,3 +37,6 @@
|
||||
[submodule "components/esp-nimble-cpp"]
|
||||
path = components/esp-nimble-cpp
|
||||
url = git@github.com:0xFEEDC0DE64/esp-nimble-cpp.git
|
||||
[submodule "components/espasyncota"]
|
||||
path = components/espasyncota
|
||||
url = git@github.com:0xFEEDC0DE64/espasyncota.git
|
||||
|
1
components/espasyncota
Submodule
1
components/espasyncota
Submodule
Submodule components/espasyncota added at b76c6c7bf2
@ -1,6 +1,7 @@
|
||||
set(headers
|
||||
ble.h
|
||||
led.h
|
||||
ota.h
|
||||
webserver.h
|
||||
wifi.h
|
||||
)
|
||||
@ -9,13 +10,15 @@ set(sources
|
||||
ble.cpp
|
||||
led.cpp
|
||||
main.cpp
|
||||
ota.cpp
|
||||
webserver.cpp
|
||||
wifi.cpp
|
||||
)
|
||||
|
||||
set(dependencies
|
||||
freertos nvs_flash esp_http_server esp_https_ota mdns app_update esp_system esp_websocket_client driver
|
||||
arduino-esp32 ArduinoJson FastLED-idf cpputils date espchrono espcpputils esp-nimble-cpp esphttpdutils espwifistack expected fmt
|
||||
arduino-esp32 ArduinoJson FastLED-idf cpputils date espchrono espasyncota espcpputils esp-nimble-cpp
|
||||
esphttpdutils espwifistack expected fmt
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
|
165
main/led.cpp
165
main/led.cpp
@ -13,9 +13,8 @@
|
||||
#include <FastLED.h>
|
||||
#include <espchrono.h>
|
||||
|
||||
#define LEDC_CHANNEL_0 0
|
||||
#define LEDC_CHANNEL_1 0
|
||||
#define LEDC_CHANNEL_2 0
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#define LEDC_TIMER_13_BIT 13
|
||||
#define LEDC_BASE_FREQ 5000
|
||||
|
||||
@ -25,10 +24,113 @@ std::array<CRGB, 5> leds;
|
||||
CRGBPalette16 currentPalette;
|
||||
TBlendType currentBlending;
|
||||
|
||||
extern CRGBPalette16 myRedWhiteBluePalette;
|
||||
extern const TProgmemPalette16 myRedWhiteBluePalette_p;
|
||||
const TProgmemPalette16 myRedWhiteBluePalette_p =
|
||||
{
|
||||
CRGB::Red,
|
||||
CRGB::Gray, // 'white' is too bright compared to red and blue
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
|
||||
CRGB::Red,
|
||||
CRGB::Gray,
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
|
||||
CRGB::Red,
|
||||
CRGB::Red,
|
||||
CRGB::Gray,
|
||||
CRGB::Gray,
|
||||
CRGB::Blue,
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
CRGB::Black
|
||||
};
|
||||
|
||||
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255);
|
||||
void ChangePalettePeriodically();
|
||||
void FillLEDsFromPaletteColors( uint8_t colorIndex);
|
||||
|
||||
espchrono::millis_clock::time_point lastRedraw{};
|
||||
}
|
||||
|
||||
void led_setup()
|
||||
{
|
||||
currentPalette = RainbowColors_p;
|
||||
currentBlending = LINEARBLEND;
|
||||
|
||||
ledcSetup(0, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(1, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(2, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
|
||||
ledcSetup(3, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(4, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(5, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
|
||||
ledcSetup(6, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(7, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(8, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
|
||||
ledcSetup(9, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(10, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(11, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
|
||||
ledcSetup(12, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(13, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(14, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
|
||||
ledcAttachPin(27, 0);
|
||||
ledcAttachPin(33, 1);
|
||||
ledcAttachPin(32, 2);
|
||||
|
||||
ledcAttachPin(23, 3);
|
||||
ledcAttachPin(25, 4);
|
||||
ledcAttachPin(26, 5);
|
||||
|
||||
ledcAttachPin(19, 6);
|
||||
ledcAttachPin(21, 7);
|
||||
ledcAttachPin(22, 8);
|
||||
|
||||
ledcAttachPin(18, 9);
|
||||
ledcAttachPin(17, 10);
|
||||
ledcAttachPin(16, 11);
|
||||
|
||||
ledcAttachPin(13, 12);
|
||||
ledcAttachPin(14, 13);
|
||||
ledcAttachPin(15, 14);
|
||||
}
|
||||
|
||||
void led_update()
|
||||
{
|
||||
if (espchrono::ago(lastRedraw) < 20ms)
|
||||
return;
|
||||
lastRedraw = espchrono::millis_clock::now();
|
||||
|
||||
ChangePalettePeriodically();
|
||||
|
||||
static uint8_t startIndex = 0;
|
||||
startIndex = startIndex + 1; /* motion speed */
|
||||
|
||||
FillLEDsFromPaletteColors(startIndex);
|
||||
|
||||
ledcAnalogWrite(0, leds[0].red);
|
||||
ledcAnalogWrite(1, leds[0].green);
|
||||
ledcAnalogWrite(2, leds[0].blue);
|
||||
|
||||
ledcAnalogWrite(3, leds[1].red);
|
||||
ledcAnalogWrite(4, leds[1].green);
|
||||
ledcAnalogWrite(5, leds[1].blue);
|
||||
|
||||
ledcAnalogWrite(6, leds[2].red);
|
||||
ledcAnalogWrite(7, leds[2].green);
|
||||
ledcAnalogWrite(8, leds[2].blue);
|
||||
|
||||
ledcAnalogWrite(9, leds[3].red);
|
||||
ledcAnalogWrite(10, leds[3].green);
|
||||
ledcAnalogWrite(11, leds[3].blue);
|
||||
|
||||
ledcAnalogWrite(12, leds[4].red);
|
||||
ledcAnalogWrite(13, leds[4].green);
|
||||
ledcAnalogWrite(14, leds[4].blue);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -83,29 +185,6 @@ void SetupPurpleAndGreenPalette()
|
||||
purple, purple, black, black );
|
||||
}
|
||||
|
||||
const TProgmemPalette16 myRedWhiteBluePalette_p =
|
||||
{
|
||||
CRGB::Red,
|
||||
CRGB::Gray, // 'white' is too bright compared to red and blue
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
|
||||
CRGB::Red,
|
||||
CRGB::Gray,
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
|
||||
CRGB::Red,
|
||||
CRGB::Red,
|
||||
CRGB::Gray,
|
||||
CRGB::Gray,
|
||||
CRGB::Blue,
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
CRGB::Black
|
||||
};
|
||||
|
||||
|
||||
void ChangePalettePeriodically()
|
||||
{
|
||||
constexpr auto millis = []() -> unsigned int { return espchrono::millis_clock::now().time_since_epoch().count(); };
|
||||
@ -128,32 +207,4 @@ void ChangePalettePeriodically()
|
||||
if( secondHand == 55) { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void led_setup()
|
||||
{
|
||||
currentPalette = RainbowColors_p;
|
||||
currentBlending = LINEARBLEND;
|
||||
|
||||
ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(LEDC_CHANNEL_1, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcSetup(LEDC_CHANNEL_2, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
|
||||
ledcAttachPin(27, LEDC_CHANNEL_0);
|
||||
ledcAttachPin(33, LEDC_CHANNEL_1);
|
||||
ledcAttachPin(32, LEDC_CHANNEL_2);
|
||||
}
|
||||
|
||||
void led_update()
|
||||
{
|
||||
ChangePalettePeriodically();
|
||||
|
||||
static uint8_t startIndex = 0;
|
||||
startIndex = startIndex + 1; /* motion speed */
|
||||
|
||||
FillLEDsFromPaletteColors( startIndex);
|
||||
|
||||
ledcAnalogWrite(LEDC_CHANNEL_0, leds[0].red);
|
||||
ledcAnalogWrite(LEDC_CHANNEL_1, leds[0].green);
|
||||
ledcAnalogWrite(LEDC_CHANNEL_2, leds[0].blue);
|
||||
}
|
||||
} // namespace
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "wifi.h"
|
||||
#include "ble.h"
|
||||
#include "webserver.h"
|
||||
#include "ota.h"
|
||||
#include "led.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
@ -65,6 +66,7 @@ extern "C" void app_main()
|
||||
wifi_setup();
|
||||
ble_setup();
|
||||
webserver_setup();
|
||||
ota_setup();
|
||||
led_setup();
|
||||
|
||||
while (true)
|
||||
@ -77,6 +79,7 @@ extern "C" void app_main()
|
||||
wifi_update();
|
||||
ble_update();
|
||||
webserver_update();
|
||||
ota_update();
|
||||
led_update();
|
||||
}
|
||||
}
|
||||
|
50
main/ota.cpp
Normal file
50
main/ota.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "ota.h"
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <delayedconstruction.h>
|
||||
#include <espasyncota.h>
|
||||
#include <espwifistack.h>
|
||||
|
||||
// local includes
|
||||
#include "wifi.h"
|
||||
|
||||
namespace {
|
||||
constexpr const char * const TAG = "OTA";
|
||||
|
||||
cpputils::DelayedConstruction<EspAsyncOta> _asyncOta;
|
||||
} // namespace
|
||||
|
||||
EspAsyncOta &asyncOta{_asyncOta.getUnsafe()};
|
||||
|
||||
void ota_setup()
|
||||
{
|
||||
ESP_LOGI(TAG, "called");
|
||||
|
||||
_asyncOta.construct();
|
||||
|
||||
if (const auto result = _asyncOta->startTask(); !result)
|
||||
{
|
||||
ESP_LOGE(TAG, "starting OTA task failed: %.*s", result.error().size(), result.error().data());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ota_update()
|
||||
{
|
||||
_asyncOta->update();
|
||||
}
|
||||
|
||||
tl::expected<void, std::string> triggerOta(std::string_view url)
|
||||
{
|
||||
ESP_LOGI(TAG, "%.*s", url.size(), url.data());
|
||||
|
||||
if (const auto result = _asyncOta->trigger(url, {}, {}, {}); !result)
|
||||
return tl::make_unexpected(std::move(result).error());
|
||||
|
||||
wifi_stack::delete_scan_result();
|
||||
|
||||
return {};
|
||||
}
|
18
main/ota.h
Normal file
18
main/ota.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <tl/expected.hpp>
|
||||
|
||||
// forward declares
|
||||
class EspAsyncOta;
|
||||
|
||||
extern EspAsyncOta &asyncOta;
|
||||
|
||||
void ota_setup();
|
||||
void ota_update();
|
||||
|
||||
tl::expected<void, std::string> triggerOta(std::string_view url);
|
@ -7,8 +7,12 @@
|
||||
// 3rdparty lib includes
|
||||
#include <esphttpdutils.h>
|
||||
#include <espcppmacros.h>
|
||||
#include <fmt/core.h>
|
||||
#include <espasyncota.h>
|
||||
|
||||
// local includes
|
||||
#include "wifi.h"
|
||||
#include "ota.h"
|
||||
|
||||
using namespace esphttpdutils;
|
||||
|
||||
@ -18,6 +22,7 @@ constexpr const char * const TAG = "WEBSERVER";
|
||||
httpd_handle_t httpdHandle;
|
||||
|
||||
esp_err_t webserver_root_handler(httpd_req_t *req);
|
||||
esp_err_t webserver_ota_handler(httpd_req_t *req);
|
||||
} // namespace
|
||||
|
||||
void webserver_setup()
|
||||
@ -34,7 +39,8 @@ void webserver_setup()
|
||||
}
|
||||
|
||||
for (const httpd_uri_t &uri : {
|
||||
httpd_uri_t { .uri = "/", .method = HTTP_GET, .handler = webserver_root_handler, .user_ctx = NULL },
|
||||
httpd_uri_t { .uri = "/", .method = HTTP_GET, .handler = webserver_root_handler, .user_ctx = NULL },
|
||||
httpd_uri_t { .uri = "/ota", .method = HTTP_GET, .handler = webserver_ota_handler, .user_ctx = NULL },
|
||||
})
|
||||
{
|
||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
||||
@ -52,8 +58,78 @@ void webserver_update()
|
||||
namespace {
|
||||
esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
{
|
||||
std::string body = "hello world";
|
||||
std::string body = fmt::format("<h1>{}</h1>", htmlentities(deviceName));
|
||||
|
||||
if (const auto otaStatus = asyncOta.status(); otaStatus == OtaCloudUpdateStatus::Idle)
|
||||
{
|
||||
body +=
|
||||
"<form action=\"/ota\">"
|
||||
"<label>ota url: <input type=\"url\" name=\"url\" required /></label>"
|
||||
"<button type=\"submit\">Start</button>"
|
||||
"</form>";
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto progress = asyncOta.progress();
|
||||
const char *color;
|
||||
switch (otaStatus)
|
||||
{
|
||||
case OtaCloudUpdateStatus::Updating: color = "#b8b800"; break;
|
||||
case OtaCloudUpdateStatus::Succeeded: color = "#13c200"; break;
|
||||
default: color = "#b80000";
|
||||
}
|
||||
|
||||
body += fmt::format("<p style=\"color: {};\">OTA: status={} progress={}", color, esphttpdutils::htmlentities(toString(otaStatus)), progress);
|
||||
|
||||
if (const auto totalSize = asyncOta.totalSize())
|
||||
{
|
||||
body += fmt::format(" totalSize={}", *totalSize);
|
||||
if (*totalSize)
|
||||
body += fmt::format(" percentage={:.1f}%", 100.f * progress / *totalSize);
|
||||
}
|
||||
|
||||
if (const auto &message = asyncOta.message(); !message.empty())
|
||||
body += fmt::format(" message={}", esphttpdutils::htmlentities(message));
|
||||
|
||||
body += "</p>\n";
|
||||
}
|
||||
|
||||
CALL_AND_EXIT(webserver_resp_send_succ, req, "text/html", body)
|
||||
}
|
||||
|
||||
esp_err_t webserver_ota_handler(httpd_req_t *req)
|
||||
{
|
||||
std::string query;
|
||||
|
||||
if (const size_t queryLength = httpd_req_get_url_query_len(req))
|
||||
{
|
||||
query.resize(queryLength);
|
||||
CALL_AND_EXIT_ON_ERROR(httpd_req_get_url_query_str, req, query.data(), query.size() + 1)
|
||||
}
|
||||
|
||||
char urlBufEncoded[256];
|
||||
if (const auto result = httpd_query_key_value(query.data(), "url", urlBufEncoded, sizeof(urlBufEncoded)); result == ESP_ERR_NOT_FOUND)
|
||||
{
|
||||
CALL_AND_EXIT(webserver_resp_send_err, req, HTTPD_400_BAD_REQUEST, "text/plain", "url parameter missing")
|
||||
}
|
||||
else if (result != ESP_OK)
|
||||
{
|
||||
const auto msg = fmt::format("httpd_query_key_value() {} failed with {}", "url", esp_err_to_name(result));
|
||||
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
|
||||
CALL_AND_EXIT(webserver_resp_send_err, req, HTTPD_400_BAD_REQUEST, "text/plain", msg)
|
||||
}
|
||||
|
||||
char urlBuf[257];
|
||||
esphttpdutils::urldecode(urlBuf, urlBufEncoded);
|
||||
|
||||
std::string_view url{urlBuf};
|
||||
|
||||
if (const auto result = triggerOta(url); !result)
|
||||
{
|
||||
ESP_LOGE(TAG, "%.*s", result.error().size(), result.error().data());
|
||||
CALL_AND_EXIT(webserver_resp_send_err, req, HTTPD_400_BAD_REQUEST, "text/plain", result.error())
|
||||
}
|
||||
|
||||
CALL_AND_EXIT(webserver_resp_send_succ, req, "text/plain", "OTA called...")
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x10000, 0x5000,
|
||||
otadata, data, ota, 0x15000, 0x2000,
|
||||
app0, app, ota_0, 0x20000, 0x1F0000,
|
||||
app0, app, ota_0, 0x20000, 0x190000,
|
||||
app1, app, ota_1, 0x220000, 0x190000,
|
||||
|
|
Reference in New Issue
Block a user