First untested version with user storage
This commit is contained in:
parent
06fdda1d93
commit
5984a233af
|
@ -2,4 +2,4 @@
|
|||
__pycache__
|
||||
*.st
|
||||
/espidf
|
||||
|
||||
/venv
|
||||
|
|
|
@ -7,13 +7,13 @@ template <class ForwardIterator, class T>
|
|||
ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T &val)
|
||||
{
|
||||
ForwardIterator it;
|
||||
iterator_traits<ForwardIterator>::difference_type count, step;
|
||||
count = distance(first, last);
|
||||
int count, step;
|
||||
count = last - first;
|
||||
while (count > 0)
|
||||
{
|
||||
it = first;
|
||||
step = count / 2;
|
||||
advance(it, step);
|
||||
it += step;
|
||||
if (*it < val)
|
||||
{
|
||||
first = ++it;
|
||||
|
@ -30,11 +30,11 @@ static String userFileName(const String &userName)
|
|||
return userDir + userName;
|
||||
}
|
||||
|
||||
bool User::load(const String &name)
|
||||
bool User::load(const String &stringId)
|
||||
{
|
||||
name_ = name;
|
||||
assert(name_.length() > 0);
|
||||
const auto fileName = userFileName(name_);
|
||||
stringId_ = stringId;
|
||||
assert(stringId_.length() > 0);
|
||||
const auto fileName = userFileName(stringId_);
|
||||
if (!portablefs::exists(fileName.c_str()))
|
||||
return false;
|
||||
|
||||
|
@ -43,7 +43,7 @@ bool User::load(const String &name)
|
|||
size_t sessionsInFile;
|
||||
file.read((uint8_t *)&sessionsInFile, sizeof(numSessions_));
|
||||
|
||||
init(name, sessionsInFile * 2);
|
||||
init(stringId, sessionsInFile * 2);
|
||||
|
||||
size_t expectedSize = sizeof(SessionIdType) * numSessions_;
|
||||
auto bytesRead = file.read((uint8_t *)sessionIds_, expectedSize);
|
||||
|
@ -52,14 +52,14 @@ bool User::load(const String &name)
|
|||
assert(expectedSize == bytesRead);
|
||||
}
|
||||
|
||||
void User::init(const String &name, size_t sessionAllocateSize)
|
||||
void User::init(const String &stringId, size_t sessionAllocateSize)
|
||||
{
|
||||
if (sessionIds_ != nullptr)
|
||||
{
|
||||
free(sessionIds_);
|
||||
sessionIds_ = nullptr;
|
||||
}
|
||||
name_ = name;
|
||||
stringId_ = stringId;
|
||||
numSessionsAllocated_ = sessionAllocateSize;
|
||||
sessionIds_ = (SessionIdType *)ps_malloc(sizeof(SessionIdType) * numSessionsAllocated_);
|
||||
numSessions_ = 0;
|
||||
|
@ -70,7 +70,7 @@ void User::save()
|
|||
if (!portablefs::exists(userDir.c_str()))
|
||||
portablefs::mkdir(userDir.c_str());
|
||||
|
||||
auto file = portablefs::open(userFileName(name_).c_str(), "w");
|
||||
auto file = portablefs::open(userFileName(stringId_).c_str(), "w");
|
||||
file.write((uint8_t *)&numSessions_, sizeof(numSessions_));
|
||||
file.write((uint8_t *)sessionIds_, sizeof(SessionIdType) * numSessions_);
|
||||
}
|
||||
|
@ -86,9 +86,9 @@ void User::freeResources()
|
|||
|
||||
void User::remove()
|
||||
{
|
||||
portablefs::remove(userFileName(name_).c_str());
|
||||
portablefs::remove(userFileName(stringId_).c_str());
|
||||
freeResources();
|
||||
name_ = "";
|
||||
stringId_ = "";
|
||||
numSessions_ = 0;
|
||||
numSessionsAllocated_ = 0;
|
||||
}
|
||||
|
@ -134,11 +134,11 @@ bool User::removeSession(SessionIdType sessionIdToRemove)
|
|||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
User *UserStorage::getUserInfo(const String &userName)
|
||||
User *UserStorage::getUserInfo(const String &stringId)
|
||||
{
|
||||
// index 0 is the unassigned user
|
||||
for (size_t i = 1; i < numUsers_; ++i)
|
||||
if (users_[i].name() == userName)
|
||||
if (users_[i].stringId() == stringId)
|
||||
return &users_[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -148,20 +148,23 @@ User *UserStorage::getUnassignedUser()
|
|||
return &users_[0];
|
||||
}
|
||||
|
||||
User *UserStorage::addNewUser(const String &userName)
|
||||
User *UserStorage::addNewUser(const String &stringId)
|
||||
{
|
||||
if (numUsers_ >= MAX_USERS)
|
||||
return nullptr;
|
||||
|
||||
if(stringId.length() >= USER_STRING_ID_MAX_LEN)
|
||||
return nullptr;
|
||||
|
||||
auto userIdx = numUsers_;
|
||||
numUsers_++;
|
||||
assert(numUsers_ < MAX_USERS);
|
||||
users_[userIdx].init(userName);
|
||||
users_[userIdx].init(stringId);
|
||||
}
|
||||
|
||||
bool UserStorage::deleteUser(const String &userName)
|
||||
bool UserStorage::deleteUser(const String &stringId)
|
||||
{
|
||||
User *userPtr = getUserInfo(userName);
|
||||
User *userPtr = getUserInfo(stringId);
|
||||
|
||||
if (userPtr == nullptr)
|
||||
return false;
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
using SessionIdType = uint32_t;
|
||||
constexpr size_t MAX_USERS = 64;
|
||||
constexpr size_t INITIAL_SESSIONS_PER_USER = 128;
|
||||
constexpr size_t USER_STRING_ID_MAX_LEN = 63;
|
||||
|
||||
struct User
|
||||
{
|
||||
public:
|
||||
User() : numSessions_(0), numSessionsAllocated_(0), sessionIds_(nullptr) {}
|
||||
|
||||
void init(const String &name, size_t sessionAllocateSize = INITIAL_SESSIONS_PER_USER);
|
||||
void init(const String &stringId_, size_t sessionAllocateSize = INITIAL_SESSIONS_PER_USER);
|
||||
void freeResources();
|
||||
|
||||
bool load(const String &name);
|
||||
|
@ -24,19 +25,19 @@ public:
|
|||
|
||||
bool hasSession(SessionIdType sessionId) const;
|
||||
|
||||
const String &name() const { return name_; }
|
||||
const String &stringId() const { return stringId_; }
|
||||
|
||||
// session access
|
||||
SessionIdType *sessionBegin() { return sessionIds_; }
|
||||
SessionIdType *sessionEnd() { return sessionIds_ + numSessions_; }
|
||||
|
||||
size_t numSessions() const { return numSessions_; }
|
||||
const SessionIdType *sessionBegin() const { return sessionIds_; }
|
||||
const SessionIdType *sessionEnd() const { return sessionIds_ + numSessions_; }
|
||||
|
||||
private:
|
||||
void growSessionArrayIfNecessary();
|
||||
|
||||
String name_;
|
||||
String stringId_;
|
||||
size_t numSessions_;
|
||||
size_t numSessionsAllocated_;
|
||||
SessionIdType *sessionIds_;
|
||||
|
@ -48,20 +49,29 @@ public:
|
|||
UserStorage()
|
||||
: numUsers_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
numUsers_ = 0;
|
||||
fillFromFileSystem();
|
||||
}
|
||||
User *getUserInfo(const String &userName);
|
||||
|
||||
User *getUserInfo(const String &stringId);
|
||||
User *getUnassignedUser();
|
||||
|
||||
User *addNewUser(const String &userName);
|
||||
bool deleteUser(const String &userName);
|
||||
User *addNewUser(const String &stringId);
|
||||
bool deleteUser(const String &stringId);
|
||||
|
||||
User *begin() { return &users_[0]; }
|
||||
User *beginWithoutUnassigned() { return &users_[1]; }
|
||||
User *end() { return &users_[numUsers_]; }
|
||||
|
||||
const User *begin() const { return &users_[0]; }
|
||||
const User *end() const { return &users_[numUsers_]; }
|
||||
|
||||
size_t numUsers() const { return numUsers_; }
|
||||
|
||||
private:
|
||||
void fillFromFileSystem();
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ data_dir = data
|
|||
|
||||
[env:esp32]
|
||||
platform = espressif32
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32
|
||||
#platform_packages =
|
||||
# framework-arduinoespressif32@https://github.com/espressif/arduino-esp32
|
||||
board = esp-wrover-kit
|
||||
#platform = espressif8266
|
||||
#board = esp_wroom_02
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
#pragma once
|
||||
#include "Dtypes.h"
|
||||
#include "UserDB.h"
|
||||
#include <ArduinoWebsockets.h>
|
||||
|
||||
template <typename T>
|
||||
|
@ -13,8 +14,8 @@ template <typename SessionT>
|
|||
class WebsocketServer
|
||||
{
|
||||
public:
|
||||
WebsocketServer(SessionManager<SessionT> &sessionManager, int port)
|
||||
: sessionManager_(sessionManager), nextFreeClient_(0), port_(port),
|
||||
WebsocketServer(SessionManager<SessionT> &sessionManager, UserStorage &userStorage, int port)
|
||||
: sessionManager_(sessionManager), userStorage_(userStorage), nextFreeClient_(0), port_(port),
|
||||
running_(false)
|
||||
{
|
||||
}
|
||||
|
@ -34,7 +35,12 @@ private:
|
|||
void sendSessionStopMessages();
|
||||
void sendNewDataMessages();
|
||||
|
||||
void sendUserList(websockets::WebsocketsClient &client);
|
||||
void sendSessionList(websockets::WebsocketsClient &client, const String &userId);
|
||||
|
||||
SessionManager<SessionT> &sessionManager_;
|
||||
UserStorage &userStorage_;
|
||||
|
||||
int nextFreeClient_;
|
||||
int port_;
|
||||
|
||||
|
@ -58,11 +64,15 @@ enum MessageType
|
|||
SESSION_STARTED = 2,
|
||||
SESSION_STOPPED = 3,
|
||||
SESSION_NEW_DATA = 4,
|
||||
ANSWER_USER_LIST = 5,
|
||||
ANSWER_SESSION_LIST = 6,
|
||||
|
||||
// from frontend to device
|
||||
START_SESSION = 5,
|
||||
STOP_SESSION = 6,
|
||||
TARE = 7
|
||||
START_SESSION = 7,
|
||||
STOP_SESSION = 8,
|
||||
TARE = 9,
|
||||
QUERY_USER_LIST = 10,
|
||||
QUERY_SESSION_LIST = 11,
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
@ -129,6 +139,7 @@ private:
|
|||
// book-keeping
|
||||
size_t numMeasurements_;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
// ------------------------------------- WebsocketServer members ---------------------------
|
||||
|
@ -137,6 +148,7 @@ template <typename SessionT>
|
|||
void WebsocketServer<SessionT>::iteration()
|
||||
{
|
||||
using namespace websockets;
|
||||
|
||||
auto onMessage = [this](WebsocketsClient &client, WebsocketsMessage message) {
|
||||
if (message.isPing())
|
||||
client.pong();
|
||||
|
@ -162,6 +174,18 @@ void WebsocketServer<SessionT>::iteration()
|
|||
case TARE:
|
||||
this->sessionManager_.tare();
|
||||
break;
|
||||
case QUERY_USER_LIST:
|
||||
this->sendUserList(client);
|
||||
break;
|
||||
case QUERY_SESSION_LIST:
|
||||
{
|
||||
StaticJsonDocument<USER_STRING_ID_MAX_LEN + 16> doc;
|
||||
deserializeMsgPack(doc, data, length);
|
||||
String userId = doc.as<String>();
|
||||
if (userId.length() > 0)
|
||||
this->sendSessionList(client, userId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
client.close(CloseReason_UnsupportedData);
|
||||
return;
|
||||
|
@ -200,10 +224,53 @@ void WebsocketServer<SessionT>::reportSessionUpdate()
|
|||
for (int i = 0; i < MAX_CONNECTIONS; ++i)
|
||||
numSentMeasurements_[i] = 0;
|
||||
}
|
||||
|
||||
sendNewDataMessages();
|
||||
}
|
||||
|
||||
template <typename SessionT>
|
||||
void WebsocketServer<SessionT>::sendUserList(websockets::WebsocketsClient &client)
|
||||
{
|
||||
const auto numUsers = userStorage_.numUsers();
|
||||
constexpr size_t constantSlack = 64;
|
||||
DynamicJsonDocument result(JSON_ARRAY_SIZE(numUsers) + numUsers * (USER_STRING_ID_MAX_LEN + 2) + constantSlack);
|
||||
JsonArray arr = result.to<JsonArray>();
|
||||
for (auto userIt = userStorage_.beginWithoutUnassigned(); userIt != userStorage_.end(); ++userIt)
|
||||
arr.add(userIt->stringId());
|
||||
|
||||
char buffer[MAX_USERS * (USER_STRING_ID_MAX_LEN + 1) + constantSlack];
|
||||
size_t bytesWritten = serializeMsgPack(result, buffer, sizeof(buffer));
|
||||
client.sendBinary(buffer, bytesWritten);
|
||||
}
|
||||
|
||||
template <typename SessionT>
|
||||
void WebsocketServer<SessionT>::sendSessionList(websockets::WebsocketsClient &client, const String &userId)
|
||||
{
|
||||
|
||||
User *user = userStorage_.getUserInfo(userId);
|
||||
if (user != nullptr)
|
||||
{
|
||||
DynamicJsonDocument result(JSON_ARRAY_SIZE(user->numSessions()) + user->numSessions() * (sizeof(SessionIdType) + 8));
|
||||
JsonArray arr = result.to<JsonArray>();
|
||||
for (SessionIdType *sIt = user->sessionBegin(); sIt != user->sessionEnd(); ++sIt)
|
||||
arr.add(*sIt);
|
||||
|
||||
size_t bytesToWrite = measureMsgPack(result);
|
||||
char *buffer = (char *)malloc(bytesToWrite);
|
||||
size_t bytesWritten = serializeMsgPack(result, buffer, bytesToWrite);
|
||||
assert(bytesWritten <= bytesToWrite);
|
||||
client.sendBinary(buffer, bytesWritten);
|
||||
free(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicJsonDocument result(JSON_ARRAY_SIZE(1) + 8);
|
||||
result.to<JsonArray>();
|
||||
char buffer[32];
|
||||
size_t bytesWritten = serializeMsgPack(result, buffer, sizeof(buffer));
|
||||
client.sendBinary(buffer, bytesWritten);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SessionT>
|
||||
void WebsocketServer<SessionT>::sendSessionStartMessages()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <HTTPClient.h>
|
||||
|
||||
#include "esp_https_ota.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "ESPmDNS.h"
|
||||
|
||||
// Own libs
|
||||
|
@ -20,12 +21,15 @@
|
|||
#include "EspHttp.h"
|
||||
#include "WebDAV.h"
|
||||
#include "WebsocketServer.h"
|
||||
#include "UserDB.h"
|
||||
|
||||
using Session_T = SimpleMeasurementSession<MeasurementT, CONFIG_SESSION_MAX_SIZE>;
|
||||
SessionManager<Session_T> sessionManager;
|
||||
|
||||
UserStorage userStorage;
|
||||
|
||||
EspHttp espHttpServer;
|
||||
WebsocketServer<Session_T> webSocketServer(sessionManager, 81);
|
||||
WebsocketServer<Session_T> webSocketServer(sessionManager, userStorage, 81);
|
||||
|
||||
WifiManager wifiManager;
|
||||
|
||||
|
@ -399,6 +403,8 @@ void setup()
|
|||
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
userStorage.init();
|
||||
|
||||
// WiFi
|
||||
String fullHostname = String(CONFIG_HOSTNAME) + getIdSuffix();
|
||||
wifiManager.begin(fullHostname);
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 327 KiB |
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
Binary file not shown.
After Width: | Height: | Size: 179 KiB |
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
Binary file not shown.
After Width: | Height: | Size: 196 KiB |
Binary file not shown.
After Width: | Height: | Size: 206 KiB |
|
@ -0,0 +1,39 @@
|
|||
Infos:
|
||||
======
|
||||
|
||||
|
||||
- Ziel: An das board soll direkt eine Wägezelle angeschlossen werden und die Messwerte per WLAN über den ESP32 verschickt werden
|
||||
- bisher hatte ich ein ESP32 Entwicklungsboard zusammen mit einem HX711 board [1]
|
||||
- das neue board soll mit standard Outdoornetzteilen funktionieren, die zwischen 12V und 25V liefern
|
||||
- als Alternative soll auch Spannungsversorgung per USB möglich sein (in aktueller Version noch nicht vorgesehen)
|
||||
aber deswegen 24V -> 5V -> 3.3V
|
||||
- Die Schaltungen sind zum Teil aus anderen Projekten/Beispielen die ich auch GitHub und in Datenblättern gefunden habe zusammenkopiert
|
||||
ich hab im schematic.pdf die Quellen dazugeschrieben
|
||||
- Ich hab das Board mit dem Webtool EasyEDA erstellt, weil ichs von dort direkt bei JLCPCB bestellen und bestücken lassen kann.
|
||||
Im Ordner sind exportierte Dateien und ein paar Screenshots. Ich habe auch einen share-link erstellt [2] mit dem mans direkt im Browser anschauen können sollte. Habs noch nie probiert, wenn was nicht geht, einfach schreiben.
|
||||
In EasyEDA kommt man auch leicht zu den Datenblättern, Bauteil auswählen, dann rechts in der Info Leiste
|
||||
|
||||
|
||||
|
||||
Kritische Stellen an denen ich nicht so richtig wusste was ich tue ;)
|
||||
=====================================================================
|
||||
|
||||
- Allgemein der Buck Converter von 24 -> 5
|
||||
- von TI gibts ein Webinterface mit dem ich das ganze dimensioniert habe (im schematic.pdf steht genaueres)
|
||||
- das PCB Layout des Buck Converters ist wegen der hohen Frequenzen ja etwas heikel.
|
||||
Im Datenblatt des LM2596SX gibts ein Beispiel Layout, aber das passt nicht genau auf die Variante die ich verbaut habe.
|
||||
In diesem Video [3] macht jemand ein Layout, das ich als Vorbild genommen hab.
|
||||
Ich weiss allerdings nicht ob man der Quelle trauen kann ;)
|
||||
- Die Kondensatoren zur 3.3V Stabilisierung sind glaube ich doppelt,
|
||||
da ich das ESP32 Entwicklungsboard und das HX711 Board "zusammenkopiert" hab.
|
||||
Zur Sicherheit hab ichs mal drauf gelassen.
|
||||
- In der aktuellen Version laufen die Input Daten der Lastzelle recht nahe an der ESP32 WiFi Antenne vorbei.
|
||||
Das ist wahrscheinlich keine Gute Idee, oder? Wie weit sollte man da Abstand halten?
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[1] https://www.amazon.de/SparkFun-SEN-13879-W%C3%A4gezelle-Verst%C3%A4rker-HX711/dp/B00NPZ4CPG
|
||||
[2] https://easyeda.com/join?type=project&key=c92800670a9943c22ecb243ed5cb0455
|
||||
[3] https://www.youtube.com/watch?v=nKOWBungcHo&t=771s
|
Binary file not shown.
Loading…
Reference in New Issue