⚡ Removes PsychicHttp dependency
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_endpoint.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
@@ -16,14 +18,13 @@ class APService : public StatefulService<APSettings> {
|
||||
void loop();
|
||||
void recoveryMode();
|
||||
|
||||
esp_err_t getStatus(PsychicRequest *request);
|
||||
esp_err_t getStatus(httpd_req_t *request);
|
||||
void status(JsonObject &root);
|
||||
APNetworkStatus getAPNetworkStatus();
|
||||
|
||||
StatefulHttpEndpoint<APSettings> endpoint;
|
||||
|
||||
private:
|
||||
PsychicHttpServer *_server;
|
||||
FSPersistence<APSettings> _persistence;
|
||||
|
||||
DNSServer *_dnsServer;
|
||||
@@ -37,4 +38,4 @@ class APService : public StatefulService<APSettings> {
|
||||
void startAP();
|
||||
void stopAP();
|
||||
void handleDNS();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <communication/comm_base.hpp>
|
||||
|
||||
class Websocket : public CommAdapterBase {
|
||||
public:
|
||||
Websocket(PsychicHttpServer &server, const char *route = "/api/ws");
|
||||
|
||||
void begin() override;
|
||||
|
||||
private:
|
||||
PsychicWebSocketHandler socket_;
|
||||
PsychicHttpServer &server_;
|
||||
const char *route_;
|
||||
|
||||
void onWSOpen(PsychicWebSocketClient *client);
|
||||
void onWSClose(PsychicWebSocketClient *client);
|
||||
esp_err_t onFrame(PsychicWebSocketRequest *request, httpd_ws_frame *frame);
|
||||
|
||||
void send(const uint8_t *data, size_t len, int cid = -1) override;
|
||||
};
|
||||
@@ -2,52 +2,43 @@
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <PsychicHttp.h>
|
||||
#include <esp_http_server.h>
|
||||
#include "platform_shared/message.pb.h"
|
||||
|
||||
#define FT_ENABLED(feature) feature
|
||||
|
||||
// ESP32 camera off by default
|
||||
#ifndef USE_CAMERA
|
||||
#define USE_CAMERA 0
|
||||
#endif
|
||||
|
||||
// ESP32 IMU on by default
|
||||
#ifndef USE_MPU6050
|
||||
#define USE_MPU6050 0
|
||||
#endif
|
||||
|
||||
// ESP32 IMU on by default
|
||||
#ifndef USE_BNO055
|
||||
#define USE_BNO055 1
|
||||
#endif
|
||||
|
||||
// ESP32 magnetometer on by default
|
||||
#ifndef USE_HMC5883
|
||||
#define USE_HMC5883 0
|
||||
#endif
|
||||
|
||||
// ESP32 barometer off by default
|
||||
#ifndef USE_BMP180
|
||||
#define USE_BMP180 0
|
||||
#endif
|
||||
|
||||
// ESP32 SONAR off by default
|
||||
#ifndef USE_USS
|
||||
#define USE_USS 0
|
||||
#endif
|
||||
|
||||
// PCA9685 Servo controller on by default
|
||||
#ifndef USE_PCA9685
|
||||
#define USE_PCA9685 1
|
||||
#endif
|
||||
|
||||
// WS2812 LED strip off by default
|
||||
#ifndef USE_WS2812
|
||||
#define USE_WS2812 0
|
||||
#endif
|
||||
|
||||
// ESP32 MDNS on by default
|
||||
#ifndef USE_MDNS
|
||||
#define USE_MDNS 1
|
||||
#endif
|
||||
@@ -78,6 +69,6 @@ void features(JsonObject& root);
|
||||
|
||||
void features_request(const socket_message_FeaturesDataRequest& fd_req, socket_message_FeaturesDataResponse& fd_res);
|
||||
|
||||
esp_err_t getFeatures(PsychicRequest* request);
|
||||
esp_err_t getFeatures(httpd_req_t* request);
|
||||
|
||||
} // namespace feature_service
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <LittleFS.h>
|
||||
#include <string>
|
||||
|
||||
@@ -16,18 +16,15 @@
|
||||
#define MDNS_SETTINGS_FILE "/config/mdnsSettings.json"
|
||||
|
||||
namespace FileSystem {
|
||||
extern PsychicUploadHandler *uploadHandler;
|
||||
|
||||
std::string listFiles(const std::string &directory, bool isRoot = true);
|
||||
bool deleteFile(const char *filename);
|
||||
bool editFile(const char *filename, const char *content);
|
||||
esp_err_t uploadFile(PsychicRequest *request, const std::string &filename, uint64_t index, uint8_t *data, size_t len,
|
||||
bool last);
|
||||
|
||||
esp_err_t getFiles(PsychicRequest *request);
|
||||
esp_err_t getConfigFile(PsychicRequest *request);
|
||||
esp_err_t handleDelete(PsychicRequest *request, JsonVariant &json);
|
||||
esp_err_t handleEdit(PsychicRequest *request, JsonVariant &json);
|
||||
esp_err_t getFiles(httpd_req_t *request);
|
||||
esp_err_t getConfigFile(httpd_req_t *request);
|
||||
esp_err_t handleDelete(httpd_req_t *request, JsonVariant &json);
|
||||
esp_err_t handleEdit(httpd_req_t *request, JsonVariant &json);
|
||||
esp_err_t mkdir(httpd_req_t *request, JsonVariant &json);
|
||||
|
||||
esp_err_t mkdir(PsychicRequest *request, JsonVariant &json);
|
||||
} // namespace FileSystem
|
||||
} // namespace FileSystem
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_endpoint.h>
|
||||
@@ -25,10 +26,10 @@ class MDNSService : public StatefulService<MDNSSettings> {
|
||||
|
||||
void begin();
|
||||
|
||||
esp_err_t getStatus(PsychicRequest *request);
|
||||
esp_err_t getStatus(httpd_req_t *request);
|
||||
void getStatus(JsonVariant &root);
|
||||
|
||||
static esp_err_t queryServices(PsychicRequest *request, JsonVariant &json);
|
||||
static esp_err_t queryServices(httpd_req_t *request, JsonVariant &json);
|
||||
|
||||
StatefulHttpEndpoint<MDNSSettings> endpoint;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <PsychicHttp.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <WiFi.h>
|
||||
#include <async_worker.h>
|
||||
|
||||
#include <features.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
@@ -31,8 +30,8 @@ class CameraService : public StatefulService<CameraSettings> {
|
||||
|
||||
esp_err_t begin();
|
||||
|
||||
esp_err_t cameraStill(PsychicRequest *request);
|
||||
esp_err_t cameraStream(PsychicRequest *request);
|
||||
esp_err_t cameraStill(httpd_req_t *request);
|
||||
esp_err_t cameraStream(httpd_req_t *request);
|
||||
|
||||
StatefulHttpEndpoint<CameraSettings> endpoint;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define ServoController_h
|
||||
|
||||
#include <Adafruit_PWMServoDriver.h>
|
||||
#include <communication/websocket_adapter.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_endpoint.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ESPmDNS.h>
|
||||
#include <PsychicHttp.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <WiFi.h>
|
||||
#include <filesystem.h>
|
||||
#include <global.h>
|
||||
@@ -13,9 +13,9 @@
|
||||
#include "platform_shared/message.pb.h"
|
||||
|
||||
namespace system_service {
|
||||
esp_err_t handleReset(PsychicRequest *request);
|
||||
esp_err_t handleRestart(PsychicRequest *request);
|
||||
esp_err_t handleSleep(PsychicRequest *request);
|
||||
esp_err_t handleReset(httpd_req_t *request);
|
||||
esp_err_t handleRestart(httpd_req_t *request);
|
||||
esp_err_t handleSleep(httpd_req_t *request);
|
||||
|
||||
void reset();
|
||||
void restart();
|
||||
@@ -25,4 +25,4 @@ void getAnalytics(socket_message_AnalyticsData &analytics);
|
||||
void getStaticSystemInformation(socket_message_StaticSystemInformation &info);
|
||||
|
||||
const char *resetReason(esp_reset_reason_t reason);
|
||||
} // namespace system_service
|
||||
} // namespace system_service
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
@@ -20,29 +22,26 @@ class StatefulHttpEndpoint {
|
||||
StatefulService<T> *statefulService)
|
||||
: _stateReader(stateReader), _stateUpdater(stateUpdater), _statefulService(statefulService) {}
|
||||
|
||||
esp_err_t handleStateUpdate(PsychicRequest *request, JsonVariant &json) {
|
||||
esp_err_t handleStateUpdate(httpd_req_t *request, JsonVariant &json) {
|
||||
JsonVariant jsonObject = json.as<JsonVariant>();
|
||||
StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||
|
||||
if (outcome == StateUpdateResult::ERROR)
|
||||
return request->reply(400);
|
||||
else if ((outcome == StateUpdateResult::CHANGED)) {
|
||||
// persist the changes to the FS
|
||||
if (outcome == StateUpdateResult::ERROR) {
|
||||
return NativeServer::sendError(request, 400, "Invalid state");
|
||||
} else if ((outcome == StateUpdateResult::CHANGED)) {
|
||||
_statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID);
|
||||
}
|
||||
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
jsonObject = response.getRoot();
|
||||
|
||||
_statefulService->read(jsonObject, _stateReader);
|
||||
|
||||
return response.send();
|
||||
JsonDocument doc;
|
||||
JsonVariant root = doc.to<JsonVariant>();
|
||||
_statefulService->read(root, _stateReader);
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
esp_err_t getState(PsychicRequest *request) {
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonVariant jsonObject = response.getRoot();
|
||||
_statefulService->read(jsonObject, _stateReader);
|
||||
return response.send();
|
||||
esp_err_t getState(httpd_req_t *request) {
|
||||
JsonDocument doc;
|
||||
JsonVariant root = doc.to<JsonVariant>();
|
||||
_statefulService->read(root, _stateReader);
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
#include <esp_http_server.h>
|
||||
#include <WiFi.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <string>
|
||||
@@ -43,9 +43,9 @@ class WiFiService : public StatefulService<WiFiSettings> {
|
||||
|
||||
const char *getHostname() { return state().hostname.c_str(); }
|
||||
|
||||
static esp_err_t handleScan(PsychicRequest *request);
|
||||
static esp_err_t getNetworks(PsychicRequest *request);
|
||||
static esp_err_t getNetworkStatus(PsychicRequest *request);
|
||||
static esp_err_t handleScan(httpd_req_t *request);
|
||||
static esp_err_t getNetworks(httpd_req_t *request);
|
||||
static esp_err_t getNetworkStatus(httpd_req_t *request);
|
||||
|
||||
StatefulHttpEndpoint<WiFiSettings> endpoint;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <PsychicHttp.h>
|
||||
#include <communication/native_server.h>
|
||||
#include "WWWData.h"
|
||||
|
||||
void mountStaticAssets(PsychicHttpServer& s);
|
||||
void mountStaticAssets(NativeServer& s);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <ap_service.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
static const char *TAG = "APService";
|
||||
|
||||
@@ -12,11 +13,11 @@ APService::~APService() {}
|
||||
|
||||
void APService::begin() { _persistence.readFromFS(); }
|
||||
|
||||
esp_err_t APService::getStatus(PsychicRequest *request) {
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonObject root = response.getRoot();
|
||||
esp_err_t APService::getStatus(httpd_req_t *request) {
|
||||
JsonDocument doc;
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
status(root);
|
||||
return response.send();
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
void APService::status(JsonObject &root) {
|
||||
@@ -73,7 +74,7 @@ void APService::startAP() {
|
||||
WiFi.softAP(state().ssid.c_str(), state().password.c_str(), state().channel, state().ssidHidden,
|
||||
state().maxClients);
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#endif
|
||||
if (!_dnsServer) {
|
||||
IPAddress apIp = WiFi.softAPIP();
|
||||
@@ -98,4 +99,4 @@ void APService::handleDNS() {
|
||||
if (_dnsServer) {
|
||||
_dnsServer->processNextRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
#include <communication/websocket_adapter.h>
|
||||
|
||||
static const char* TAG = "Websocket";
|
||||
|
||||
Websocket::Websocket(PsychicHttpServer& server, const char* route) : server_(server), route_(route) {
|
||||
socket_.onOpen(std::bind(&Websocket::onWSOpen, this, std::placeholders::_1));
|
||||
socket_.onClose(std::bind(&Websocket::onWSClose, this, std::placeholders::_1));
|
||||
socket_.onFrame(std::bind(&Websocket::onFrame, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void Websocket::begin() { server_.on(route_, &socket_); }
|
||||
|
||||
void Websocket::onWSOpen(PsychicWebSocketClient* client) {
|
||||
ESP_LOGI(TAG, "Client connected: %s [%u]", client->remoteIP().toString().c_str(), client->socket());
|
||||
sendPong(client->socket());
|
||||
}
|
||||
|
||||
void Websocket::onWSClose(PsychicWebSocketClient* client) {
|
||||
ESP_LOGI(TAG, "Client disconnected: %s [%u]", client->remoteIP().toString().c_str(), client->socket());
|
||||
removeClient(client->socket());
|
||||
}
|
||||
|
||||
esp_err_t Websocket::onFrame(PsychicWebSocketRequest* request, httpd_ws_frame* frame) {
|
||||
if (frame->type != HTTPD_WS_TYPE_BINARY) {
|
||||
ESP_LOGW(TAG, "Expected binary frame, got type %d", frame->type);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
handleIncoming(frame->payload, frame->len, request->client()->socket());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void Websocket::send(const uint8_t* data, size_t len, int cid) {
|
||||
if (cid >= 0) {
|
||||
auto* client = socket_.getClient(cid);
|
||||
if (client) {
|
||||
esp_err_t err = client->sendMessage(HTTPD_WS_TYPE_BINARY, data, len);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to send message to client %d: %s (len=%u)", cid, esp_err_to_name(err), len);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Client %d not found for send", cid);
|
||||
}
|
||||
} else {
|
||||
socket_.sendAll(HTTPD_WS_TYPE_BINARY, data, len);
|
||||
}
|
||||
}
|
||||
+7
-13
@@ -1,28 +1,24 @@
|
||||
#include <features.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
namespace feature_service {
|
||||
|
||||
// New function to print all feature flags to log
|
||||
void printFeatureConfiguration() {
|
||||
ESP_LOGI("Features", "====================== FEATURE FLAGS ======================");
|
||||
ESP_LOGI("Features", "Firmware version: %s, name: %s, target: %s", APP_VERSION, APP_NAME, BUILD_TARGET);
|
||||
|
||||
// Core features
|
||||
ESP_LOGI("Features", "USE_CAMERA: %s", USE_CAMERA ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "USE_MOTION: %s", USE_MOTION ? "enabled" : "disabled");
|
||||
|
||||
// Sensors
|
||||
ESP_LOGI("Features", "USE_BNO055: %s", USE_BNO055 ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "USE_MPU6050: %s", USE_MPU6050 ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "USE_HMC5883: %s", USE_HMC5883 ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "USE_BMP180: %s", USE_BMP180 ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "USE_USS: %s", USE_USS ? "enabled" : "disabled");
|
||||
|
||||
// Peripherals
|
||||
ESP_LOGI("Features", "USE_PCA9685: %s", USE_PCA9685 ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "USE_WS2812: %s", USE_WS2812 ? "enabled" : "disabled");
|
||||
|
||||
// Web services
|
||||
ESP_LOGI("Features", "USE_MDNS: %s", USE_MDNS ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "EMBED_WEBAPP: %s", EMBED_WEBAPP ? "enabled" : "disabled");
|
||||
ESP_LOGI("Features", "KINEMATICS_VARIANT: %s", KINEMATICS_VARIANT_STR);
|
||||
@@ -45,9 +41,7 @@ void features_request(const socket_message_FeaturesDataRequest& fd_req, socket_m
|
||||
fd_res.variant = const_cast<char*>(KINEMATICS_VARIANT_STR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void features(JsonObject &root) {
|
||||
void features(JsonObject& root) {
|
||||
root["camera"] = USE_CAMERA ? true : false;
|
||||
root["imu"] = (USE_MPU6050 || USE_BNO055) ? true : false;
|
||||
root["mag"] = (USE_HMC5883 || USE_BNO055) ? true : false;
|
||||
@@ -63,11 +57,11 @@ void features(JsonObject &root) {
|
||||
root["variant"] = KINEMATICS_VARIANT_STR;
|
||||
}
|
||||
|
||||
esp_err_t getFeatures(PsychicRequest *request) {
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonObject root = response.getRoot();
|
||||
esp_err_t getFeatures(httpd_req_t* request) {
|
||||
JsonDocument doc;
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
features(root);
|
||||
return response.send();
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
} // namespace feature_service
|
||||
} // namespace feature_service
|
||||
|
||||
+26
-57
@@ -1,62 +1,53 @@
|
||||
#include <filesystem.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
static const char *TAG = "FileService";
|
||||
|
||||
namespace FileSystem {
|
||||
|
||||
PsychicUploadHandler *uploadHandler;
|
||||
esp_err_t getFiles(httpd_req_t *request) {
|
||||
std::string files = listFiles("/");
|
||||
httpd_resp_set_type(request, "application/json");
|
||||
return httpd_resp_send(request, files.c_str(), files.length());
|
||||
}
|
||||
|
||||
class Initializer {
|
||||
public:
|
||||
Initializer() {
|
||||
uploadHandler = new PsychicUploadHandler();
|
||||
uploadHandler->onUpload([](PsychicRequest *request, const String &filename, uint64_t index, uint8_t *data,
|
||||
size_t len, bool last) -> esp_err_t {
|
||||
return uploadFile(request, std::string(filename.c_str()), index, data, len, last);
|
||||
});
|
||||
uploadHandler->onRequest([](PsychicRequest *request) { return request->reply(200); });
|
||||
esp_err_t getConfigFile(httpd_req_t *request) {
|
||||
const char *uri = request->uri;
|
||||
std::string path = "/config" + std::string(uri).substr(11);
|
||||
if (!ESP_FS.exists(path.c_str())) {
|
||||
return NativeServer::sendError(request, 404, "File not found");
|
||||
}
|
||||
};
|
||||
|
||||
static Initializer initializer;
|
||||
|
||||
esp_err_t getFiles(PsychicRequest *request) { return request->reply(200, "application/json", listFiles("/").c_str()); }
|
||||
|
||||
esp_err_t getConfigFile(PsychicRequest *request) {
|
||||
String path = "/config" + request->uri().substring(11);
|
||||
if (!ESP_FS.exists(path)) {
|
||||
return request->reply(404, "text/plain", "File not found");
|
||||
}
|
||||
File file = ESP_FS.open(path, "r");
|
||||
File file = ESP_FS.open(path.c_str(), "r");
|
||||
if (!file) {
|
||||
return request->reply(500, "text/plain", "Failed to open file");
|
||||
return NativeServer::sendError(request, 500, "Failed to open file");
|
||||
}
|
||||
String content = file.readString();
|
||||
file.close();
|
||||
return request->reply(200, "application/json", content.c_str());
|
||||
httpd_resp_set_type(request, "application/json");
|
||||
return httpd_resp_send(request, content.c_str(), content.length());
|
||||
}
|
||||
|
||||
esp_err_t handleDelete(PsychicRequest *request, JsonVariant &json) {
|
||||
esp_err_t handleDelete(httpd_req_t *request, JsonVariant &json) {
|
||||
if (json.is<JsonObject>()) {
|
||||
const char *filename = json["file"].as<const char *>();
|
||||
ESP_LOGI(TAG, "Deleting file: %s", filename);
|
||||
return deleteFile(filename) ? request->reply(200) : request->reply(500);
|
||||
return deleteFile(filename) ? NativeServer::sendOk(request)
|
||||
: NativeServer::sendError(request, 500, "Delete failed");
|
||||
}
|
||||
return request->reply(400);
|
||||
return NativeServer::sendError(request, 400, "Invalid request");
|
||||
}
|
||||
|
||||
esp_err_t handleEdit(PsychicRequest *request, JsonVariant &json) {
|
||||
esp_err_t handleEdit(httpd_req_t *request, JsonVariant &json) {
|
||||
if (json.is<JsonObject>()) {
|
||||
const char *filename = json["file"].as<const char *>();
|
||||
const char *content = json["content"].as<const char *>();
|
||||
ESP_LOGI(TAG, "Editing file: %s", filename);
|
||||
return editFile(filename, content) ? request->reply(200) : request->reply(500);
|
||||
return editFile(filename, content) ? NativeServer::sendOk(request)
|
||||
: NativeServer::sendError(request, 500, "Edit failed");
|
||||
}
|
||||
return request->reply(400);
|
||||
return NativeServer::sendError(request, 400, "Invalid request");
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
bool deleteFile(const char *filename) { return ESP_FS.remove(filename); }
|
||||
|
||||
std::string listFiles(const std::string &directory, bool isRoot) {
|
||||
@@ -89,28 +80,6 @@ std::string listFiles(const std::string &directory, bool isRoot) {
|
||||
return output;
|
||||
}
|
||||
|
||||
esp_err_t uploadFile(PsychicRequest *request, const std::string &filename, uint64_t index, uint8_t *data, size_t len,
|
||||
bool last) {
|
||||
File file;
|
||||
std::string path = "/www/" + filename;
|
||||
ESP_LOGI(TAG, "Writing %d/%d bytes to: %s\n", (int)index + (int)len, request->contentLength(), path.c_str());
|
||||
|
||||
if (last) ESP_LOGI(TAG, "%s is finished. Total bytes: %d\n", path.c_str(), (int)index + (int)len);
|
||||
|
||||
file = ESP_FS.open(path.c_str(), !index ? FILE_WRITE : FILE_APPEND);
|
||||
if (!file) {
|
||||
ESP_LOGE(TAG, "Failed to open file");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (!file.write(data, len)) {
|
||||
ESP_LOGE(TAG, "Write failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool editFile(const char *filename, const char *content) {
|
||||
File file = ESP_FS.open(filename, FILE_WRITE);
|
||||
if (!file) return false;
|
||||
@@ -120,10 +89,10 @@ bool editFile(const char *filename, const char *content) {
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t mkdir(PsychicRequest *request, JsonVariant &json) {
|
||||
esp_err_t mkdir(httpd_req_t *request, JsonVariant &json) {
|
||||
const char *path = json["path"].as<const char *>();
|
||||
ESP_LOGI(TAG, "Creating directory: %s", path);
|
||||
return ESP_FS.mkdir(path) ? request->reply(200) : request->reply(500);
|
||||
return ESP_FS.mkdir(path) ? NativeServer::sendOk(request) : NativeServer::sendError(request, 500, "mkdir failed");
|
||||
}
|
||||
|
||||
} // namespace FileSystem
|
||||
} // namespace FileSystem
|
||||
|
||||
+83
-93
@@ -1,5 +1,4 @@
|
||||
#include <Arduino.h>
|
||||
#include <PsychicHttp.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <WiFi.h>
|
||||
#include <Wire.h>
|
||||
@@ -11,7 +10,8 @@
|
||||
#include <peripherals/servo_controller.h>
|
||||
#include <peripherals/led_service.h>
|
||||
#include <peripherals/camera_service.h>
|
||||
#include <communication/websocket_adapter.h>
|
||||
#include <communication/native_server.h>
|
||||
#include <communication/native_websocket.h>
|
||||
#include <features.h>
|
||||
#include <motion.h>
|
||||
#include <wifi_service.h>
|
||||
@@ -21,11 +21,8 @@
|
||||
|
||||
#include <www_mount.hpp>
|
||||
|
||||
// Communication
|
||||
PsychicHttpServer server;
|
||||
Websocket socket {server, "/api/ws"};
|
||||
NativeWebsocket socket {nativeServer, "/api/ws"};
|
||||
|
||||
// Core
|
||||
Peripherals peripherals;
|
||||
ServoController servoController;
|
||||
MotionService motionService;
|
||||
@@ -39,99 +36,91 @@ Camera::CameraService cameraService;
|
||||
MDNSService mdnsService;
|
||||
#endif
|
||||
|
||||
// Service
|
||||
WiFiService wifiService;
|
||||
APService apService;
|
||||
|
||||
void setupServer() {
|
||||
server.config.max_uri_handlers = 50 + WWW_ASSETS_COUNT;
|
||||
server.config.stack_size = 32768; // 32KB
|
||||
server.maxUploadSize = 1000000; // 1 MB;
|
||||
server.listen(80);
|
||||
server.on("/api/system/reset", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return system_service::handleReset(request); });
|
||||
server.on("/api/system/restart", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return system_service::handleRestart(request); });
|
||||
server.on("/api/system/sleep", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return system_service::handleSleep(request); });
|
||||
nativeServer.config(50 + WWW_ASSETS_COUNT, 32768, 1000000);
|
||||
nativeServer.listen(80);
|
||||
|
||||
nativeServer.on("/api/system/reset", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return system_service::handleReset(request); });
|
||||
nativeServer.on("/api/system/restart", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return system_service::handleRestart(request); });
|
||||
nativeServer.on("/api/system/sleep", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return system_service::handleSleep(request); });
|
||||
#if USE_CAMERA
|
||||
server.on("/api/camera/still", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return cameraService.cameraStill(request); });
|
||||
server.on("/api/camera/stream", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return cameraService.cameraStream(request); });
|
||||
server.on("/api/camera/settings", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return cameraService.endpoint.getState(request); });
|
||||
server.on("/api/camera/settings", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
|
||||
nativeServer.on("/api/camera/still", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return cameraService.cameraStill(request); });
|
||||
nativeServer.on("/api/camera/stream", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return cameraService.cameraStream(request); });
|
||||
nativeServer.on("/api/camera/settings", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return cameraService.endpoint.getState(request); });
|
||||
nativeServer.on("/api/camera/settings", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
|
||||
return cameraService.endpoint.handleStateUpdate(request, json);
|
||||
});
|
||||
#endif
|
||||
server.on("/api/servo/config", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return servoController.endpoint.getState(request); });
|
||||
server.on("/api/servo/config", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
|
||||
nativeServer.on("/api/servo/config", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return servoController.endpoint.getState(request); });
|
||||
nativeServer.on("/api/servo/config", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
|
||||
return servoController.endpoint.handleStateUpdate(request, json);
|
||||
});
|
||||
|
||||
// WiFi
|
||||
server.on("/api/wifi/sta/settings", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return wifiService.endpoint.getState(request); });
|
||||
server.on("/api/wifi/sta/settings", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
|
||||
nativeServer.on("/api/wifi/sta/settings", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return wifiService.endpoint.getState(request); });
|
||||
nativeServer.on("/api/wifi/sta/settings", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
|
||||
return wifiService.endpoint.handleStateUpdate(request, json);
|
||||
});
|
||||
server.on("/api/wifi/scan", HTTP_GET, [&](PsychicRequest *request) { return wifiService.handleScan(request); });
|
||||
server.on("/api/wifi/networks", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return wifiService.getNetworks(request); });
|
||||
server.on("/api/wifi/sta/status", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return wifiService.getNetworkStatus(request); });
|
||||
nativeServer.on("/api/wifi/scan", HTTP_GET, [&](httpd_req_t *request) { return wifiService.handleScan(request); });
|
||||
nativeServer.on("/api/wifi/networks", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return wifiService.getNetworks(request); });
|
||||
nativeServer.on("/api/wifi/sta/status", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return wifiService.getNetworkStatus(request); });
|
||||
|
||||
// AP
|
||||
server.on("/api/ap/status", HTTP_GET, [&](PsychicRequest *request) { return apService.getStatus(request); });
|
||||
server.on("/api/ap/settings", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return apService.endpoint.getState(request); });
|
||||
server.on("/api/ap/settings", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
|
||||
nativeServer.on("/api/ap/status", HTTP_GET, [&](httpd_req_t *request) { return apService.getStatus(request); });
|
||||
nativeServer.on("/api/ap/settings", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return apService.endpoint.getState(request); });
|
||||
nativeServer.on("/api/ap/settings", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
|
||||
return apService.endpoint.handleStateUpdate(request, json);
|
||||
});
|
||||
|
||||
// Peripherals
|
||||
server.on("/api/peripherals", HTTP_GET,
|
||||
[&](PsychicRequest *request) { return peripherals.endpoint.getState(request); });
|
||||
server.on("/api/peripherals", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
|
||||
nativeServer.on("/api/peripherals", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return peripherals.endpoint.getState(request); });
|
||||
nativeServer.on("/api/peripherals", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
|
||||
return peripherals.endpoint.handleStateUpdate(request, json);
|
||||
});
|
||||
|
||||
// MDNS
|
||||
#if FT_ENABLED(USE_MDNS)
|
||||
server.on("/api/mdns", HTTP_GET, [&](PsychicRequest *request) { return mdnsService.endpoint.getState(request); });
|
||||
server.on("/api/mdns", HTTP_POST, [&](PsychicRequest *request, JsonVariant &json) {
|
||||
nativeServer.on("/api/mdns", HTTP_GET,
|
||||
[&](httpd_req_t *request) { return mdnsService.endpoint.getState(request); });
|
||||
nativeServer.on("/api/mdns", HTTP_POST, [&](httpd_req_t *request, JsonVariant &json) {
|
||||
return mdnsService.endpoint.handleStateUpdate(request, json);
|
||||
});
|
||||
server.on("/api/mdns/status", HTTP_GET, [&](PsychicRequest *request) { return mdnsService.getStatus(request); });
|
||||
server.on("/api/mdns/query", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return mdnsService.queryServices(request, json); });
|
||||
nativeServer.on("/api/mdns/status", HTTP_GET, [&](httpd_req_t *request) { return mdnsService.getStatus(request); });
|
||||
nativeServer.on("/api/mdns/query", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return mdnsService.queryServices(request, json); });
|
||||
#endif
|
||||
|
||||
// Filesystem
|
||||
server.on("/api/config/*", HTTP_GET, [](PsychicRequest *request) { return FileSystem::getConfigFile(request); });
|
||||
server.on("/api/files", HTTP_GET, [&](PsychicRequest *request) { return FileSystem::getFiles(request); });
|
||||
server.on("/api/files", HTTP_POST, FileSystem::uploadHandler);
|
||||
server.on("/api/files/delete", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return FileSystem::handleDelete(request, json); });
|
||||
server.on("/api/files/edit", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return FileSystem::handleEdit(request, json); });
|
||||
server.on("/api/files/mkdir", HTTP_POST,
|
||||
[&](PsychicRequest *request, JsonVariant &json) { return FileSystem::mkdir(request, json); });
|
||||
nativeServer.on("/api/config/*", HTTP_GET, [](httpd_req_t *request) { return FileSystem::getConfigFile(request); });
|
||||
nativeServer.on("/api/files", HTTP_GET, [&](httpd_req_t *request) { return FileSystem::getFiles(request); });
|
||||
nativeServer.on("/api/files/delete", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return FileSystem::handleDelete(request, json); });
|
||||
nativeServer.on("/api/files/edit", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return FileSystem::handleEdit(request, json); });
|
||||
nativeServer.on("/api/files/mkdir", HTTP_POST,
|
||||
[&](httpd_req_t *request, JsonVariant &json) { return FileSystem::mkdir(request, json); });
|
||||
#if EMBED_WEBAPP
|
||||
mountStaticAssets(server);
|
||||
mountStaticAssets(nativeServer);
|
||||
#endif
|
||||
server.on("/*", HTTP_OPTIONS, [](PsychicRequest *request) { // CORS handling
|
||||
PsychicResponse response(request);
|
||||
response.setCode(200);
|
||||
return response.send();
|
||||
nativeServer.on("/*", HTTP_OPTIONS, [](httpd_req_t *request) {
|
||||
httpd_resp_set_status(request, "200 OK");
|
||||
return httpd_resp_send(request, nullptr, 0);
|
||||
});
|
||||
DefaultHeaders::Instance().addHeader("Server", APP_NAME);
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Max-Age", "86400");
|
||||
nativeServer.addDefaultHeader("Server", APP_NAME);
|
||||
nativeServer.addDefaultHeader("Access-Control-Allow-Origin", "*");
|
||||
nativeServer.addDefaultHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||
nativeServer.addDefaultHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
||||
nativeServer.addDefaultHeader("Access-Control-Max-Age", "86400");
|
||||
}
|
||||
|
||||
void setupEventSocket() {
|
||||
@@ -164,76 +153,77 @@ void setupEventSocket() {
|
||||
data.active ? servoController.activate() : servoController.deactivate();
|
||||
});
|
||||
|
||||
socket.on<socket_message_FSUploadData>([&](const socket_message_FSUploadData &data, int clientId) {
|
||||
FileSystemWS::fsHandler.handleUploadData(data);
|
||||
});
|
||||
socket.on<socket_message_FSUploadData>(
|
||||
[&](const socket_message_FSUploadData &data, int clientId) { FileSystemWS::fsHandler.handleUploadData(data); });
|
||||
|
||||
using CorrelationHandler =
|
||||
std::function<void(const socket_message_CorrelationRequest &, socket_message_CorrelationResponse &, int)>;
|
||||
static std::map<pb_size_t, CorrelationHandler> correlationHandlers = {
|
||||
{socket_message_CorrelationRequest_features_data_request_tag, // Features data
|
||||
{socket_message_CorrelationRequest_features_data_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_features_data_response_tag;
|
||||
feature_service::features_request(req.request.features_data_request, res.response.features_data_response);
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_i2c_scan_data_request_tag, // i2c data
|
||||
{socket_message_CorrelationRequest_i2c_scan_data_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_i2c_scan_data_tag;
|
||||
peripherals.scanI2C();
|
||||
peripherals.getI2CScanProto(res.response.i2c_scan_data);
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_imu_calibrate_execute_tag, // Calibration request
|
||||
{socket_message_CorrelationRequest_imu_calibrate_execute_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_imu_calibrate_data_tag;
|
||||
res.response.imu_calibrate_data.success = peripherals.calibrateIMU();
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_system_information_request_tag, // All system information data
|
||||
{socket_message_CorrelationRequest_system_information_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_system_information_response_tag;
|
||||
res.response.system_information_response.has_analytics_data = true;
|
||||
res.response.system_information_response.has_static_system_information = true;
|
||||
system_service::getAnalytics(res.response.system_information_response.analytics_data);
|
||||
system_service::getStaticSystemInformation(res.response.system_information_response.static_system_information);
|
||||
res.which_response = socket_message_CorrelationResponse_system_information_response_tag;
|
||||
res.response.system_information_response.has_analytics_data = true;
|
||||
res.response.system_information_response.has_static_system_information = true;
|
||||
system_service::getAnalytics(res.response.system_information_response.analytics_data);
|
||||
system_service::getStaticSystemInformation(
|
||||
res.response.system_information_response.static_system_information);
|
||||
}},
|
||||
|
||||
// Filesystem operations
|
||||
{socket_message_CorrelationRequest_fs_delete_request_tag, // Delete file/directory
|
||||
{socket_message_CorrelationRequest_fs_delete_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_fs_delete_response_tag;
|
||||
res.response.fs_delete_response = FileSystemWS::fsHandler.handleDelete(req.request.fs_delete_request);
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_fs_mkdir_request_tag, // Create directory
|
||||
{socket_message_CorrelationRequest_fs_mkdir_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_fs_mkdir_response_tag;
|
||||
res.response.fs_mkdir_response = FileSystemWS::fsHandler.handleMkdir(req.request.fs_mkdir_request);
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_fs_list_request_tag, // List directory
|
||||
{socket_message_CorrelationRequest_fs_list_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_fs_list_response_tag;
|
||||
res.response.fs_list_response = FileSystemWS::fsHandler.handleList(req.request.fs_list_request);
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_fs_download_request_tag, // Streaming download (no response, streams data)
|
||||
{socket_message_CorrelationRequest_fs_download_request_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
FileSystemWS::fsHandler.handleDownloadRequest(req.request.fs_download_request, clientId);
|
||||
res.status_code = 0;
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_fs_upload_start_tag, // Upload start
|
||||
{socket_message_CorrelationRequest_fs_upload_start_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_fs_upload_start_response_tag;
|
||||
res.response.fs_upload_start_response = FileSystemWS::fsHandler.handleUploadStart(req.request.fs_upload_start, clientId);
|
||||
res.response.fs_upload_start_response =
|
||||
FileSystemWS::fsHandler.handleUploadStart(req.request.fs_upload_start, clientId);
|
||||
}},
|
||||
|
||||
{socket_message_CorrelationRequest_fs_cancel_transfer_tag, // Cancel transfer
|
||||
{socket_message_CorrelationRequest_fs_cancel_transfer_tag,
|
||||
[](const auto &req, auto &res, int clientId) {
|
||||
res.which_response = socket_message_CorrelationResponse_fs_cancel_transfer_response_tag;
|
||||
res.response.fs_cancel_transfer_response = FileSystemWS::fsHandler.handleCancelTransfer(req.request.fs_cancel_transfer);
|
||||
res.response.fs_cancel_transfer_response =
|
||||
FileSystemWS::fsHandler.handleCancelTransfer(req.request.fs_cancel_transfer);
|
||||
}},
|
||||
};
|
||||
|
||||
@@ -339,4 +329,4 @@ void setup() {
|
||||
ESP_LOGI("main", "Finished booting");
|
||||
}
|
||||
|
||||
void loop() { vTaskDelete(nullptr); }
|
||||
void loop() { vTaskDelete(nullptr); }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mdns_service.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
static const char *TAG = "MDNSService";
|
||||
|
||||
@@ -64,11 +65,11 @@ void MDNSService::addServices() {
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t MDNSService::getStatus(PsychicRequest *request) {
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonVariant root = response.getRoot();
|
||||
esp_err_t MDNSService::getStatus(httpd_req_t *request) {
|
||||
JsonDocument doc;
|
||||
JsonVariant root = doc.to<JsonVariant>();
|
||||
getStatus(root);
|
||||
return response.send();
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
void MDNSService::getStatus(JsonVariant &root) {
|
||||
@@ -76,12 +77,12 @@ void MDNSService::getStatus(JsonVariant &root) {
|
||||
root["started"] = _started;
|
||||
}
|
||||
|
||||
esp_err_t MDNSService::queryServices(PsychicRequest *request, JsonVariant &json) {
|
||||
esp_err_t MDNSService::queryServices(httpd_req_t *request, JsonVariant &json) {
|
||||
std::string service = json["service"].as<std::string>();
|
||||
std::string proto = json["protocol"].as<std::string>();
|
||||
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonVariant root = response.getRoot();
|
||||
JsonDocument doc;
|
||||
JsonVariant root = doc.to<JsonVariant>();
|
||||
|
||||
ESP_LOGI(TAG, "Querying for service: %s, protocol: %s", service.c_str(), proto.c_str());
|
||||
|
||||
@@ -96,5 +97,5 @@ esp_err_t MDNSService::queryServices(PsychicRequest *request, JsonVariant &json)
|
||||
serviceObj["port"] = MDNS.port(i);
|
||||
}
|
||||
|
||||
return response.send();
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <peripherals/camera_service.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
namespace Camera {
|
||||
|
||||
@@ -83,78 +84,60 @@ esp_err_t CameraService::begin() {
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t CameraService::cameraStill(PsychicRequest *request) {
|
||||
esp_err_t CameraService::cameraStill(httpd_req_t *request) {
|
||||
camera_fb_t *fb = safe_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
request->reply(500, "text/plain", "Camera capture failed");
|
||||
return ESP_FAIL;
|
||||
return NativeServer::sendError(request, 500, "Camera capture failed");
|
||||
}
|
||||
PsychicStreamResponse response = PsychicStreamResponse(request, "image/jpeg", "capture.jpg");
|
||||
response.beginSend();
|
||||
response.write(fb->buf, fb->len);
|
||||
|
||||
httpd_resp_set_type(request, "image/jpeg");
|
||||
httpd_resp_set_hdr(request, "Content-Disposition", "inline; filename=capture.jpg");
|
||||
esp_err_t res = httpd_resp_send(request, (const char *)fb->buf, fb->len);
|
||||
esp_camera_fb_return(fb);
|
||||
return response.endSend();
|
||||
return res;
|
||||
}
|
||||
|
||||
void streamTask(void *pv) {
|
||||
esp_err_t CameraService::cameraStream(httpd_req_t *request) {
|
||||
httpd_resp_set_type(request, _STREAM_CONTENT_TYPE);
|
||||
|
||||
camera_fb_t *fb = NULL;
|
||||
char part_buf[64];
|
||||
uint8_t *buf = NULL;
|
||||
size_t buf_len = 0;
|
||||
esp_err_t res = ESP_OK;
|
||||
|
||||
PsychicRequest *request = static_cast<PsychicRequest *>(pv);
|
||||
|
||||
httpd_req_t *copy = nullptr;
|
||||
res = httpd_req_async_handler_begin(request->request(), ©);
|
||||
if (res != ESP_OK) {
|
||||
return;
|
||||
}
|
||||
PsychicHttpServer *server = request->server();
|
||||
PsychicRequest new_request = PsychicRequest(server, copy);
|
||||
request = &new_request;
|
||||
|
||||
PsychicStreamResponse response = PsychicStreamResponse(request, _STREAM_CONTENT_TYPE);
|
||||
camera_fb_t *fb = NULL;
|
||||
|
||||
char *part_buf[64];
|
||||
size_t buf_len = 0;
|
||||
uint8_t *buf = NULL;
|
||||
int64_t fr_start = esp_timer_get_time();
|
||||
|
||||
response.beginSend();
|
||||
|
||||
for (;;) {
|
||||
while (res == ESP_OK) {
|
||||
fb = safe_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE("Stream", "Camera capture failed");
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
break;
|
||||
}
|
||||
if (fb->format != PIXFORMAT_JPEG) {
|
||||
if (!frame2jpg(fb, 80, &buf, &buf_len)) break;
|
||||
if (!frame2jpg(fb, 80, &buf, &buf_len)) {
|
||||
esp_camera_fb_return(fb);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
buf_len = fb->len;
|
||||
buf = fb->buf;
|
||||
}
|
||||
|
||||
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, buf_len);
|
||||
size_t w = response.write((const char *)part_buf, hlen);
|
||||
w += response.write((const char *)buf, buf_len);
|
||||
w += response.write((char *)_STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
if (w == 62) break;
|
||||
size_t hlen = snprintf(part_buf, 64, _STREAM_PART, buf_len);
|
||||
|
||||
res = httpd_resp_send_chunk(request, part_buf, hlen);
|
||||
if (res == ESP_OK) res = httpd_resp_send_chunk(request, (const char *)buf, buf_len);
|
||||
if (res == ESP_OK) res = httpd_resp_send_chunk(request, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
|
||||
esp_camera_fb_return(fb);
|
||||
safe_sensor_return();
|
||||
buf = NULL;
|
||||
taskYIELD();
|
||||
int64_t delay = 30000ll - esp_timer_get_time() - fr_start;
|
||||
if (delay > 0) vTaskDelay(pdMS_TO_TICKS(delay));
|
||||
}
|
||||
ESP_LOGI("Stream", "Stream ended");
|
||||
response.endSend();
|
||||
httpd_req_async_handler_complete(copy);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
esp_err_t CameraService::cameraStream(PsychicRequest *request) {
|
||||
xTaskCreate(streamTask, "Stream client task", 4096, request, 4, nullptr);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
vTaskDelay(pdMS_TO_TICKS(30));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stream ended");
|
||||
httpd_resp_send_chunk(request, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -193,4 +176,4 @@ void CameraService::updateCamera() {
|
||||
safe_sensor_return();
|
||||
}
|
||||
|
||||
} // namespace Camera
|
||||
} // namespace Camera
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
#include "system_service.h"
|
||||
#include <communication/native_server.h>
|
||||
|
||||
namespace system_service {
|
||||
|
||||
static const char *TAG = "SystemService";
|
||||
|
||||
esp_err_t handleReset(PsychicRequest *request) {
|
||||
esp_err_t handleReset(httpd_req_t *request) {
|
||||
reset();
|
||||
return request->reply(200);
|
||||
return NativeServer::sendOk(request);
|
||||
}
|
||||
|
||||
esp_err_t handleRestart(PsychicRequest *request) {
|
||||
esp_err_t handleRestart(httpd_req_t *request) {
|
||||
restart();
|
||||
return request->reply(200);
|
||||
return NativeServer::sendOk(request);
|
||||
}
|
||||
|
||||
esp_err_t handleSleep(PsychicRequest *request) {
|
||||
esp_err_t handleSleep(httpd_req_t *request) {
|
||||
sleep();
|
||||
return request->reply(200);
|
||||
return NativeServer::sendOk(request);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
@@ -141,4 +142,4 @@ const char *resetReason(esp_reset_reason_t reason) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace system_service
|
||||
} // namespace system_service
|
||||
|
||||
+19
-21
@@ -1,4 +1,5 @@
|
||||
#include <wifi_service.h>
|
||||
#include <communication/native_server.h>
|
||||
|
||||
WiFiService::WiFiService()
|
||||
: _persistence(WiFiSettings::read, WiFiSettings::update, this, WIFI_SETTINGS_FILE),
|
||||
@@ -38,25 +39,28 @@ void WiFiService::reconfigureWiFiConnection() {
|
||||
|
||||
void WiFiService::loop() { EXECUTE_EVERY_N_MS(reconnectDelay, manageSTA()); }
|
||||
|
||||
esp_err_t WiFiService::handleScan(PsychicRequest *request) {
|
||||
esp_err_t WiFiService::handleScan(httpd_req_t *request) {
|
||||
if (WiFi.scanComplete() != -1) {
|
||||
WiFi.scanDelete();
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
return request->reply(202);
|
||||
httpd_resp_set_status(request, "202 Accepted");
|
||||
return httpd_resp_send(request, nullptr, 0);
|
||||
}
|
||||
|
||||
esp_err_t WiFiService::getNetworks(PsychicRequest *request) {
|
||||
esp_err_t WiFiService::getNetworks(httpd_req_t *request) {
|
||||
int numNetworks = WiFi.scanComplete();
|
||||
if (numNetworks == -1)
|
||||
return request->reply(202);
|
||||
else if (numNetworks < -1)
|
||||
if (numNetworks == -1) {
|
||||
httpd_resp_set_status(request, "202 Accepted");
|
||||
return httpd_resp_send(request, nullptr, 0);
|
||||
} else if (numNetworks < -1) {
|
||||
return handleScan(request);
|
||||
}
|
||||
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonObject root = response.getRoot();
|
||||
JsonDocument doc;
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
getNetworks(root);
|
||||
return response.send();
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
void WiFiService::setupMDNS(const char *hostname) {
|
||||
@@ -80,11 +84,11 @@ void WiFiService::getNetworks(JsonObject &root) {
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t WiFiService::getNetworkStatus(PsychicRequest *request) {
|
||||
PsychicJsonResponse response = PsychicJsonResponse(request, false);
|
||||
JsonObject root = response.getRoot();
|
||||
esp_err_t WiFiService::getNetworkStatus(httpd_req_t *request) {
|
||||
JsonDocument doc;
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
getNetworkStatus(root);
|
||||
return response.send();
|
||||
return NativeServer::sendJson(request, 200, doc);
|
||||
}
|
||||
|
||||
void WiFiService::getNetworkStatus(JsonObject &root) {
|
||||
@@ -116,12 +120,10 @@ void WiFiService::manageSTA() {
|
||||
}
|
||||
|
||||
void WiFiService::connectToWiFi() {
|
||||
// reset availability flag for all stored networks
|
||||
for (auto &network : state().wifiSettings) {
|
||||
network.available = false;
|
||||
}
|
||||
|
||||
// scanning for available networks
|
||||
int scanResult = WiFi.scanNetworks();
|
||||
if (scanResult == WIFI_SCAN_FAILED) {
|
||||
ESP_LOGE("WiFiSettingsService", "WiFi scan failed.");
|
||||
@@ -130,7 +132,6 @@ void WiFiService::connectToWiFi() {
|
||||
} else {
|
||||
ESP_LOGI("WiFiSettingsService", "%d networks found.", scanResult);
|
||||
|
||||
// find the best network to connect
|
||||
wifi_settings_t *bestNetwork = nullptr;
|
||||
int32_t bestNetworkDb = FACTORY_WIFI_RSSI_THRESHOLD;
|
||||
|
||||
@@ -178,19 +179,16 @@ void WiFiService::connectToWiFi() {
|
||||
|
||||
void WiFiService::configureNetwork(wifi_settings_t &network) {
|
||||
if (network.staticIPConfig) {
|
||||
// configure for static IP
|
||||
WiFi.config(network.localIP, network.gatewayIP, network.subnetMask, network.dnsIP1, network.dnsIP2);
|
||||
} else {
|
||||
// configure for DHCP
|
||||
WiFi.config(IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0));
|
||||
}
|
||||
WiFi.setHostname(state().hostname.c_str());
|
||||
|
||||
// attempt to connect to the network
|
||||
WiFi.begin(network.ssid.c_str(), network.password.c_str());
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -210,4 +208,4 @@ void WiFiService::onStationModeStop(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
void WiFiService::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
ESP_LOGI("WiFiStatus", "WiFi Got IP. localIP=%s, hostName=%s", WiFi.localIP().toString().c_str(),
|
||||
WiFi.getHostname());
|
||||
}
|
||||
}
|
||||
|
||||
+14
-19
@@ -1,30 +1,25 @@
|
||||
#include "www_mount.hpp"
|
||||
|
||||
static esp_err_t web_send(PsychicRequest* req, const WebAsset& asset) {
|
||||
PsychicResponse resp(req);
|
||||
resp.setCode(200);
|
||||
resp.setContentType(asset.mime);
|
||||
if (asset.gz) resp.addHeader("Content-Encoding", "gzip");
|
||||
if (WWW_OPT.add_vary) resp.addHeader("Vary", "Accept-Encoding");
|
||||
static esp_err_t web_send(httpd_req_t* req, const WebAsset& asset) {
|
||||
httpd_resp_set_status(req, "200 OK");
|
||||
httpd_resp_set_type(req, asset.mime);
|
||||
if (asset.gz) httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
|
||||
if (WWW_OPT.add_vary) httpd_resp_set_hdr(req, "Vary", "Accept-Encoding");
|
||||
|
||||
char cc[64];
|
||||
snprintf(cc, sizeof(cc), "public, immutable, max-age=%u", WWW_OPT.max_age);
|
||||
resp.addHeader("Cache-Control", cc);
|
||||
httpd_resp_set_hdr(req, "Cache-Control", cc);
|
||||
|
||||
char et[34];
|
||||
snprintf(et, sizeof(et), "\"%08x\"", asset.etag);
|
||||
resp.addHeader("ETag", et);
|
||||
resp.setContent(asset.data, asset.len);
|
||||
return resp.send();
|
||||
httpd_resp_set_hdr(req, "ETag", et);
|
||||
|
||||
return httpd_resp_send(req, (const char*)asset.data, asset.len);
|
||||
}
|
||||
|
||||
void mountStaticAssets(PsychicHttpServer& server) {
|
||||
static uint8_t buf[sizeof(PsychicWebHandler) * WWW_ASSETS_COUNT];
|
||||
void mountStaticAssets(NativeServer& server) {
|
||||
for (size_t i = 0; i < WWW_ASSETS_COUNT; i++) {
|
||||
const WebAsset* a = &WWW_ASSETS[i];
|
||||
auto* handle = new (&buf[i * sizeof(PsychicWebHandler)]) PsychicWebHandler();
|
||||
handle->onRequest([a](PsychicRequest* req) { return web_send(req, *a); });
|
||||
server.on(a->uri, HTTP_GET, handle);
|
||||
if (strcmp(a->uri, WWW_OPT.default_uri) == 0) {
|
||||
server.defaultEndpoint->setHandler(handle);
|
||||
}
|
||||
server.on(a->uri, HTTP_GET, [a](httpd_req_t* req) { return web_send(req, *a); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@ build_src_flags =
|
||||
test_ignore = test_embedded
|
||||
board_build.filesystem = littlefs
|
||||
lib_deps =
|
||||
hoeken/PsychicHttp@^1.2.1
|
||||
ArduinoJson@>=7.0.0
|
||||
teckel12/NewPing@^1.9.7
|
||||
jrowberg/I2Cdevlib-MPU6050@^1.0.0
|
||||
|
||||
Reference in New Issue
Block a user