Fixed scale tare

This commit is contained in:
Martin Bauer 2020-06-05 20:55:01 +02:00
parent 123c2a534b
commit daa2454e71
14 changed files with 622 additions and 44 deletions

View File

@ -17,4 +17,4 @@ inline String toString(const T & t) {
return String(t); return String(t);
} }
#define assert(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__)) #define assert_msg(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__))

View File

@ -0,0 +1,181 @@
#pragma once
#ifdef PLATFORM_ESP32
#include "SPIFFS.h"
namespace portablefs
{
using File = ::File;
class Dir
{
public:
Dir() {}
Dir(const String &path)
: root_(SPIFFS.open(path))
{
//next();
}
bool next()
{
file_ = root_.openNextFile();
return file_;
}
bool isFile()
{
return !file_.isDirectory();
}
bool isDirectory()
{
return file_.isDirectory();
}
String fileName() const
{
return file_.name();
}
size_t fileSize() const
{
return file_.size();
}
private:
File root_;
File file_;
};
inline Dir openDir(const String &path)
{
return Dir(path);
}
inline File open(const char *name, const char *mode)
{
return SPIFFS.open(name, mode);
}
inline bool exists(const char *name)
{
return SPIFFS.exists(name);
}
inline bool remove(const char *name)
{
return SPIFFS.remove(name);
}
inline bool mkdir(const char *name)
{
return SPIFFS.mkdir(name);
}
} // namespace portablefs
#endif
#ifdef PLATFORM_ESP8266
#include <FS.h>
namespace portablefs
{
using Dir;
} // namespace portablefs
#endif
#ifdef PLATFORM_NATIVE
#include <string>
#include <fstream>
#include <filesystem>
#include "MockDtypes.h"
namespace fs = std::filesystem;
namespace portablefs
{
const std::string basePath = "./base";
class Dir
{
public:
Dir() {}
Dir(const String &path)
: it_(fs::directory_iterator(path).begin()),
end_(fs::directory_iterator(path).end()),
firstIncremented_(false)
{
}
bool next()
{
if (!firstIncremented_)
firstIncremented_ = true;
else
++it_;
return it_ != end_;
}
bool isFile()
{
return file.is_regular_file();
}
bool isDirectory()
{
return it_.is_directory();
}
String fileName() const
{
return it_.path().filename().string();
}
size_t fileSize() const
{
return it_.file_size();
}
private:
fs::directory_iterator it_;
fs::directory_iterator end_;
bool firstIncremented_;
};
inline Dir openDir(const String &path)
{
return Dir(path);
}
inline File open(const char *name, const char *mode)
{
if(mode == "r")
return fopen()
return SPIFFS.open(name, mode);
}
inline bool exists(const char *name)
{
return SPIFFS.exists(name);
}
inline bool remove(const char *name)
{
return SPIFFS.remove(name);
}
inline bool mkdir(const char *name)
{
return SPIFFS.mkdir(name);
}
} // namespace portablefs
#endif

View File

@ -7,6 +7,7 @@
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string>
typedef uint32_t uint_t; typedef uint32_t uint_t;
@ -39,4 +40,7 @@ inline std::string toString(const T & t) {
return stream.str(); return stream.str();
} }
class String : public std::string
{};
#define assert(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__)) #define assert(EXPRESSION, MSG) ((EXPRESSION) ? (void)0 : _assert(#EXPRESSION, #MSG, __FILE__, __LINE__))

View File

@ -4,14 +4,16 @@
class MockScale class MockScale
{ {
public: public:
MockScale( uint16_t valueMin=0, uint16_t valueMax=50) MockScale( uint16_t valueMin=0, uint16_t valueMax=10)
: valueMin_(valueMin), valueMax_(valueMax), currentValue_(valueMin), direction(1) : valueMin_(valueMin), valueMax_(valueMax), currentValue_(valueMin), direction(1)
{} {}
bool measure(uint16_t & measurementOut) { bool measure(uint16_t & measurementOut) {
currentValue_ += direction; currentValue_ += direction;
if ( currentValue_ >= valueMax_) if ( currentValue_ >= valueMax_) {
direction = -1; direction = -1;
valueMax_ += 2;
}
else if ( currentValue_ <= valueMin_ ) else if ( currentValue_ <= valueMin_ )
direction = +1; direction = +1;

View File

@ -1,4 +1,5 @@
#include "HX711.h" #include "HX711.h"
#include "ConfigHardware.h"
#include <cstdint> #include <cstdint>
@ -9,8 +10,11 @@ public:
bool measure(uint16_t & measurementOut) { bool measure(uint16_t & measurementOut) {
if (hx711_.is_ready()) if (hx711_.is_ready())
{ {
uint32_t value = hx711_.get_value(MEASUREMENT_AVG_COUNT); long value = hx711_.read_average(CONFIG_MEASUREMENT_AVG_COUNT) - offset_;
measurementOut = (int16_t)(value / DIVIDER); if(value > 0)
measurementOut = (int16_t)(value / DIVIDER);
else
measurementOut = 0;
return true; return true;
} }
else else
@ -22,9 +26,10 @@ public:
}; };
void tare(uint32_t numMeasurementsToAverage=50) { void tare(uint32_t numMeasurementsToAverage=50) {
hx711_.tare(numMeasurementsToAverage); offset_ = hx711_.read_average(numMeasurementsToAverage);
} }
private: private:
HX711 hx711_; HX711 hx711_;
long offset_ = 0;
}; };

View File

@ -23,7 +23,7 @@ public:
Serial.println("Starting session rotate"); Serial.println("Starting session rotate");
rotate(); rotate();
const bool secondInsertSuccess = currentChunk->addPoint(measurement); const bool secondInsertSuccess = currentChunk->addPoint(measurement);
assert(secondInsertSuccess, "Session: insertion after rotation failed"); assert_msg(secondInsertSuccess, "Session: insertion after rotation failed");
// TODO check that there is place for file - remove old files // TODO check that there is place for file - remove old files
} }
return true; return true;
@ -52,7 +52,7 @@ public:
encoder.template sendArrayHeader<Measurement_T>(lastIdx - startIdx); encoder.template sendArrayHeader<Measurement_T>(lastIdx - startIdx);
while(startIdx < lastIdx) while(startIdx < lastIdx)
startIdx = serializeChunk(encoder, startIdx); startIdx = serializeChunk(encoder, startIdx);
assert(startIdx == lastIdx, "Not all data was sent"); assert_msg(startIdx == lastIdx, "Not all data was sent");
} }
uint32_t getStartTime() const { uint32_t getStartTime() const {
@ -88,18 +88,18 @@ private:
template< typename Encoder_T> template< typename Encoder_T>
uint32_t serializeChunk(Encoder_T & encoder, uint32_t startIdx) const { uint32_t serializeChunk(Encoder_T & encoder, uint32_t startIdx) const {
assert( startIdx < currentChunk->getStartIndex() + currentChunk->numMeasurements(), assert_msg( startIdx < currentChunk->getStartIndex() + currentChunk->numMeasurements(),
"serializeChunk: invalid startIdx" ); "serializeChunk: invalid startIdx" );
if( startIdx >= currentChunk->getStartIndex() ) { if( startIdx >= currentChunk->getStartIndex() ) {
const auto localStartIdx = startIdx - currentChunk->getStartIndex(); const auto localStartIdx = startIdx - currentChunk->getStartIndex();
const auto numElements = currentChunk->numMeasurements() - localStartIdx; const auto numElements = currentChunk->numMeasurements() - localStartIdx;
assert(numElements <= currentChunk->numMeasurements(), "Internal problem in serializeChunk"); assert_msg(numElements <= currentChunk->numMeasurements(), "Internal problem in serializeChunk");
encoder.sendArrayPartialContents( currentChunk->getDataPointer() + localStartIdx, numElements ); encoder.sendArrayPartialContents( currentChunk->getDataPointer() + localStartIdx, numElements );
return currentChunk->getStartIndex() + currentChunk->numMeasurements(); return currentChunk->getStartIndex() + currentChunk->numMeasurements();
} else if( startIdx >= otherChunk->getStartIndex() && otherChunkFilled() ) { } else if( startIdx >= otherChunk->getStartIndex() && otherChunkFilled() ) {
encoder.sendArrayPartialContents( otherChunk->getDataPointer(), otherChunk->numMeasurements() ); encoder.sendArrayPartialContents( otherChunk->getDataPointer(), otherChunk->numMeasurements() );
assert( otherChunk->numMeasurements(), CHUNK_SIZE ); assert_msg( otherChunk->numMeasurements(), CHUNK_SIZE );
return otherChunk->getStartIndex() + otherChunk->numMeasurements(); return otherChunk->getStartIndex() + otherChunk->numMeasurements();
} else { } else {
if( encoder.getSizeCountMode() ) { if( encoder.getSizeCountMode() ) {

View File

@ -1,7 +1,43 @@
#pragma once #pragma once
#include "StreamingMsgPackEncoder.h" #include "StreamingMsgPackEncoder.h"
#include <FS.h> #include "FilesystemAbstraction.h"
#ifdef USE_ESP32
struct WriterAdaptor
{
File * f;
void write(const char * ptr, size_t size) {
f->write(reinterpret_cast<const uint8_t *>(ptr), size);
}
};
class SpiffsStorageWriter {
public:
SpiffsStorageWriter(const String &fileName) :
f_(SPIFFS.open(fileName, "w")),
adaptor_{&f_},
encoder_(&adaptor_),
fileName_(fileName)
{
bool success = f_;
Serial.println(success);
}
~SpiffsStorageWriter() {
f_.close();
Serial.println(fileName_);
Serial.println(SPIFFS.exists(fileName_));
}
StreamingMsgPackEncoder<WriterAdaptor> &encoder() { return encoder_; }
private:
File f_;
WriterAdaptor adaptor_;
StreamingMsgPackEncoder<WriterAdaptor> encoder_;
String fileName_;
};
#else
class SpiffsStorageWriter { class SpiffsStorageWriter {
public: public:
@ -26,6 +62,11 @@ private:
String fileName_; String fileName_;
}; };
#endif
class SpiffsStorageReader class SpiffsStorageReader
{ {

View File

@ -19,6 +19,7 @@ struct DummyWriter {
void write(const void*, uint32_t) {} void write(const void*, uint32_t) {}
}; };
class CopyWriter { class CopyWriter {
public: public:
CopyWriter(uint8_t * bufferToWrite) CopyWriter(uint8_t * bufferToWrite)
@ -193,8 +194,8 @@ public:
uint32_t elementsToSkip = 0; uint32_t elementsToSkip = 0;
if( sentBytes_ < offsetToStart_ ) { if( sentBytes_ < offsetToStart_ ) {
elementsToSkip = (offsetToStart_ - sentBytes_) / sizeof(T); elementsToSkip = (offsetToStart_ - sentBytes_) / sizeof(T);
assert((offsetToStart_ - sentBytes_) % sizeof(T) == 0, assert_msg((offsetToStart_ - sentBytes_) % sizeof(T) == 0,
"Looks like previous sent operation send fraction of an element."); "Looks like previous sent operation send fraction of an element.");
} }
if( elementsToSkip >= length) { if( elementsToSkip >= length) {
sentBytes_ += sizeof(T) * length; sentBytes_ += sizeof(T) * length;
@ -241,7 +242,7 @@ private:
if( sentBytes_ < offsetToStart_ ) { if( sentBytes_ < offsetToStart_ ) {
// already sent // already sent
sentBytes_ += sizeRequired; sentBytes_ += sizeRequired;
assert( sentBytes_ <= offsetToStart_, "Partial sending not supported by this function" ); assert_msg( sentBytes_ <= offsetToStart_, "Partial sending not supported by this function" );
return; return;
} }

192
lib/userdb/UserDB.cpp Normal file
View File

@ -0,0 +1,192 @@
#include "UserDB.h"
#include "FilesystemAbstraction.h"
const String userDir = "/u/";
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);
while (count > 0)
{
it = first;
step = count / 2;
advance(it, step);
if (*it < val)
{
first = ++it;
count -= step + 1;
}
else
count = step;
}
return first;
}
static String userFileName(const String &userName)
{
return userDir + userName;
}
bool User::load(const String &name)
{
name_ = name;
assert(name_.length() > 0);
const auto fileName = userFileName(name_);
if (!portablefs::exists(fileName.c_str()))
return false;
auto file = portablefs::open(fileName.c_str(), "r");
size_t sessionsInFile;
file.read((uint8_t *)&sessionsInFile, sizeof(numSessions_));
init(name, sessionsInFile * 2);
size_t expectedSize = sizeof(SessionIdType) * numSessions_;
auto bytesRead = file.read((uint8_t *)sessionIds_, expectedSize);
numSessions_ = sessionsInFile;
assert(expectedSize == bytesRead);
}
void User::init(const String &name, size_t sessionAllocateSize)
{
if (sessionIds_ != nullptr)
{
free(sessionIds_);
sessionIds_ = nullptr;
}
name_ = name;
numSessionsAllocated_ = sessionAllocateSize;
sessionIds_ = (SessionIdType *)ps_malloc(sizeof(SessionIdType) * numSessionsAllocated_);
numSessions_ = 0;
}
void User::save()
{
if (!portablefs::exists(userDir.c_str()))
portablefs::mkdir(userDir.c_str());
auto file = portablefs::open(userFileName(name_).c_str(), "w");
file.write((uint8_t *)&numSessions_, sizeof(numSessions_));
file.write((uint8_t *)sessionIds_, sizeof(SessionIdType) * numSessions_);
}
void User::freeResources()
{
if (sessionIds_ != nullptr)
{
free(sessionIds_);
sessionIds_ = nullptr;
}
}
void User::remove()
{
portablefs::remove(userFileName(name_).c_str());
freeResources();
name_ = "";
numSessions_ = 0;
numSessionsAllocated_ = 0;
}
void User::growSessionArrayIfNecessary()
{
assert(numSessions_ <= numSessionsAllocated_);
if (numSessions_ < numSessionsAllocated_)
return;
numSessionsAllocated_ *= 2;
sessionIds_ = (SessionIdType *)ps_realloc(sessionIds_, numSessionsAllocated_);
assert(numSessions_ < numSessionsAllocated_);
}
void User::insertSession(SessionIdType newSessionId)
{
growSessionArrayIfNecessary();
assert(numSessionsAllocated_ > numSessions_);
SessionIdType *insertPos = lower_bound(sessionIds_, sessionIds_ + numSessions_, newSessionId);
const size_t moveStartIdx = sessionIds_ + numSessions_ - insertPos;
for (size_t i = numSessions_ - 1; i >= moveStartIdx; --i)
sessionIds_[i + 1] = sessionIds_[i];
sessionIds_[moveStartIdx] = newSessionId;
numSessions_ += 1;
}
bool User::removeSession(SessionIdType sessionIdToRemove)
{
SessionIdType *removePos = lower_bound(sessionIds_, sessionIds_ + numSessions_, sessionIdToRemove);
const size_t removeIdx = sessionIds_ + numSessions_ - removePos;
if (sessionIds_[removeIdx] != sessionIdToRemove)
return false;
for (size_t i = removeIdx; i < numSessions_ - 1; ++i)
sessionIds_[i] = sessionIds_[i + 1];
numSessions_ -= 1;
return true;
}
// --------------------------------------------------------------------------------------------------------------------
User *UserStorage::getUserInfo(const String &userName)
{
// index 0 is the unassigned user
for (size_t i = 1; i < numUsers_; ++i)
if (users_[i].name() == userName)
return &users_[i];
return nullptr;
}
User *UserStorage::getUnassignedUser()
{
return &users_[0];
}
User *UserStorage::addNewUser(const String &userName)
{
if (numUsers_ >= MAX_USERS)
return nullptr;
auto userIdx = numUsers_;
numUsers_++;
assert(numUsers_ < MAX_USERS);
users_[userIdx].init(userName);
}
bool UserStorage::deleteUser(const String &userName)
{
User *userPtr = getUserInfo(userName);
if (userPtr == nullptr)
return false;
size_t userIdx = userPtr - users_;
userPtr->remove();
assert(numUsers_ > 0);
if (userIdx != numUsers_ - 1)
users_[userIdx] = users_[numUsers_ - 1];
}
void UserStorage::fillFromFileSystem()
{
for (size_t i = 0; i < numUsers_; ++i)
users_[i].freeResources();
numUsers_ = 1;
users_[0].load("_unassigned");
portablefs::Dir d(userDir);
while (d.next())
{
if (d.isFile() && d.fileName()[0] != '_')
{
users_[numUsers_].load(d.fileName());
++numUsers_;
}
}
}

73
lib/userdb/UserDB.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#ifndef PLATFORM_NATIVE
#include <Arduino.h>
#endif
using SessionIdType = uint32_t;
constexpr size_t MAX_USERS = 64;
constexpr size_t INITIAL_SESSIONS_PER_USER = 128;
struct User
{
public:
User() : numSessions_(0), numSessionsAllocated_(0), sessionIds_(nullptr) {}
void init(const String &name, size_t sessionAllocateSize = INITIAL_SESSIONS_PER_USER);
void freeResources();
bool load(const String &name);
void save();
void remove();
bool valid() const { return sessionIds_ != nullptr; }
void insertSession(SessionIdType sessionId);
bool removeSession(SessionIdType sessionId);
bool hasSession(SessionIdType sessionId) const;
const String &name() const { return name_; }
// session access
SessionIdType *sessionBegin() { return sessionIds_; }
SessionIdType *sessionEnd() { return sessionIds_ + numSessions_; }
const SessionIdType *sessionBegin() const { return sessionIds_; }
const SessionIdType *sessionEnd() const { return sessionIds_ + numSessions_; }
private:
void growSessionArrayIfNecessary();
String name_;
size_t numSessions_;
size_t numSessionsAllocated_;
SessionIdType *sessionIds_;
};
class UserStorage
{
public:
UserStorage()
: numUsers_(0)
{
fillFromFileSystem();
}
User *getUserInfo(const String &userName);
User *getUnassignedUser();
User *addNewUser(const String &userName);
bool deleteUser(const String &userName);
User *begin() { return &users_[0]; }
User *end() { return &users_[numUsers_]; }
const User *begin() const { return &users_[0]; }
const User *end() const { return &users_[numUsers_]; }
private:
void fillFromFileSystem();
User users_[MAX_USERS];
size_t numUsers_;
};

View File

@ -1,5 +1,6 @@
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <FS.h> #include "FilesystemAbstraction.h"
#define FLASH_TEXT(name) const char *name #define FLASH_TEXT(name) const char *name
@ -35,7 +36,7 @@ public:
WebdavFileListCallback(const String &path) WebdavFileListCallback(const String &path)
: path_(path), headerWritten_(false), finished_(false) : path_(path), headerWritten_(false), finished_(false)
{ {
dir_ = SPIFFS.openDir(path); dir_ = portablefs::openDir(path);
} }
size_t operator()(uint8_t *buffer, size_t maxLen, size_t index) size_t operator()(uint8_t *buffer, size_t maxLen, size_t index)
@ -104,11 +105,11 @@ public:
} }
size_t bytesWritten = buffer - bufferStart; size_t bytesWritten = buffer - bufferStart;
assert(bytesWritten < maxLen, "Written too much!"); assert_msg(bytesWritten < maxLen, "Written too much!");
Serial.print("Bytes written "); //Serial.print("Bytes written ");
Serial.println(bytesWritten); //Serial.println(bytesWritten);
Serial.print("Max bytes "); //Serial.print("Max bytes ");
Serial.println(maxLen); //Serial.println(maxLen);
return bytesWritten; return bytesWritten;
} }
@ -122,7 +123,7 @@ private:
{ {
size_t size = 0; size_t size = 0;
auto fileBase = fileZero.substring(0, fileZero.indexOf('_')); auto fileBase = fileZero.substring(0, fileZero.indexOf('_'));
auto newDirInstance = SPIFFS.openDir(path_); auto newDirInstance = portablefs::openDir(path_);
while (newDirInstance.next()) while (newDirInstance.next())
if (newDirInstance.isFile() && newDirInstance.fileName().startsWith(fileBase)) if (newDirInstance.isFile() && newDirInstance.fileName().startsWith(fileBase))
size += newDirInstance.fileSize(); size += newDirInstance.fileSize();
@ -136,7 +137,7 @@ private:
buffer += len; buffer += len;
} }
Dir dir_; portablefs::Dir dir_;
const String path_; const String path_;
bool headerWritten_; bool headerWritten_;
bool finished_; bool finished_;
@ -147,7 +148,7 @@ bool deleteMeasurementFiles(const String &stName, const String &folder)
String baseName = folder + "/" + stName.substring(0, stName.indexOf(".")); String baseName = folder + "/" + stName.substring(0, stName.indexOf("."));
int counter = 0; int counter = 0;
{ {
auto d = SPIFFS.openDir(folder); auto d = portablefs::openDir(folder);
while (d.next()) while (d.next())
if (d.isFile() && d.fileName().startsWith(baseName)) if (d.isFile() && d.fileName().startsWith(baseName))
++counter; ++counter;

View File

@ -1,11 +1,29 @@
#pragma once
#include <cstdint> #include <cstdint>
//#define _HW_V_20
// HX711 load cell // HX711 load cell
#ifdef USE_ESP32
#ifdef _HW_V_20
const int CONFIG_SCALE_DOUT_PIN = 23;
const int CONFIG_SCALE_SCK_PIN = 22;
#else
const int CONFIG_SCALE_DOUT_PIN = 22;
const int CONFIG_SCALE_SCK_PIN = 23;
#endif
#else
const int CONFIG_SCALE_DOUT_PIN = D2; const int CONFIG_SCALE_DOUT_PIN = D2;
const int CONFIG_SCALE_SCK_PIN = D3; const int CONFIG_SCALE_SCK_PIN = D3;
const uint8_t CONFIG_TARE_AVG_COUNT = 50; // number of measurements in tare-phase (to find 0 ) #endif
const int CONFIG_VALUE_DIVIDER = 128; // uint32 measurements are divided by this factor, before stored in uint16_t const uint8_t CONFIG_MEASUREMENT_AVG_COUNT = 1; // number of measurements in normal phase
const uint8_t CONFIG_TARE_AVG_COUNT = 6; // number of measurements in tare-phase (to find 0 )
const int CONFIG_MEASURE_DELAY = 100; // interval in ms between measurements const int CONFIG_MEASURE_DELAY = 100; // interval in ms between measurements
//const int CONFIG_VALUE_DIVIDER = 8; // uint32 measurements are divided by this factor, before stored in uint16_t
const int CONFIG_VALUE_DIVIDER = 256; // uint32 measurements are divided by this factor, before stored in uint16_t
const uint32_t CONFIG_SESSION_CHUNK_SIZE = 1024; //1024*8 - 16 * sizeof(uint32_t); const uint32_t CONFIG_SESSION_CHUNK_SIZE = 1024; //1024*8 - 16 * sizeof(uint32_t);

View File

@ -1,7 +1,12 @@
#ifdef USE_ESP32
#include "SPIFFS.h"
#else
#include <FS.h> #include <FS.h>
#endif
inline void printDeviceInfo() inline void printDeviceInfo()
{ {
/*
FSInfo fs_info; FSInfo fs_info;
SPIFFS.info(fs_info); SPIFFS.info(fs_info);
@ -66,4 +71,5 @@ inline void printDeviceInfo()
str += "\r\n"; str += "\r\n";
} }
Serial.print(str); Serial.print(str);
*/
} }

View File

@ -1,7 +1,13 @@
#define USE_ESP32
// Arduino & ESP headers // Arduino & ESP headers
#include <Arduino.h> #include <Arduino.h>
#ifdef USE_ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h> #include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h> #include <ESPAsyncWebServer.h>
#include <WiFiUdp.h> // for NTP #include <WiFiUdp.h> // for NTP
#include <NTPClient.h> // for NTP #include <NTPClient.h> // for NTP
@ -9,6 +15,7 @@
// Own libs // Own libs
#include "Dtypes.h" #include "Dtypes.h"
#include "MockScale.h" #include "MockScale.h"
#include "Scale.h"
#include "MeasurementSession.h" #include "MeasurementSession.h"
#include "SpiffsStorage.h" #include "SpiffsStorage.h"
#include "DeviceInfoLog.h" #include "DeviceInfoLog.h"
@ -46,6 +53,7 @@ public:
void stopMeasurements() { void stopMeasurements() {
measuring_ = false; measuring_ = false;
session.finalize();
} }
bool isMeasuring() const { bool isMeasuring() const {
@ -54,12 +62,14 @@ public:
void iteration() { void iteration() {
if( ! measuring_ ) { if( ! measuring_ ) {
//Serial.println("Disabled");
return; return;
} }
uint16_t measurement; uint16_t measurement=-1;
scale.measure(measurement); scale.measure(measurement);
session.addPoint(measurement); session.addPoint(measurement);
Serial.print("Measurement: ");
Serial.println(measurement);
if( lastCallTime_ != 0) { if( lastCallTime_ != 0) {
const long cycleDuration = millis() - lastCallTime_; const long cycleDuration = millis() - lastCallTime_;
if( cycleDuration <= CONFIG_MEASURE_DELAY) if( cycleDuration <= CONFIG_MEASURE_DELAY)
@ -69,8 +79,7 @@ public:
else else
{ {
const long skipped = (cycleDuration / CONFIG_MEASURE_DELAY); const long skipped = (cycleDuration / CONFIG_MEASURE_DELAY);
Serial.print("Warning: measurements skipped: "); //Serial.printf("Warning: measurements skipped: %d, cycleDuration %d", skipped, cycleDuration);
Serial.println(skipped);
for(int i=0; i < skipped; ++i) for(int i=0; i < skipped; ++i)
session.addPoint(measurement); session.addPoint(measurement);
@ -84,7 +93,8 @@ public:
Session_T & getSession() { return session; } Session_T & getSession() { return session; }
private: private:
MockScale scale; Scale<CONFIG_VALUE_DIVIDER> scale;
//MockScale scale;
Session_T session; Session_T session;
bool measuring_; bool measuring_;
long lastCallTime_; long lastCallTime_;
@ -100,12 +110,18 @@ template<typename Session_T>
void httpSetup(SessionManager<Session_T> * sessionManager) void httpSetup(SessionManager<Session_T> * sessionManager)
{ {
server.on("/api/session/start", HTTP_POST | HTTP_GET, [sessionManager](AsyncWebServerRequest * req) { server.on("/api/session/start", HTTP_POST | HTTP_GET, [sessionManager](AsyncWebServerRequest * req) {
req->send(200, "text/plain", F("OK")); AsyncWebServerResponse *response = req->beginResponse(200, "text/plain", F("OK"));
response->addHeader("Access-Control-Allow-Origin", "*");
req->send(response);
//req->send(200, "text/plain", F("OK"));
sessionManager->startMeasurements(); sessionManager->startMeasurements();
Serial.println("Started measurements"); Serial.println("Started measurements");
}); });
server.on("/api/session/stop", HTTP_POST | HTTP_GET, [sessionManager](AsyncWebServerRequest * req) { server.on("/api/session/stop", HTTP_POST | HTTP_GET, [sessionManager](AsyncWebServerRequest * req) {
req->send(200, "text/plain", F("OK")); AsyncWebServerResponse *response = req->beginResponse(200, "text/plain", F("OK"));
response->addHeader("Access-Control-Allow-Origin", "*");
req->send(response);
//req->send(200, "text/plain", F("OK"));
sessionManager->stopMeasurements(); sessionManager->stopMeasurements();
Serial.println("Stopped measurements"); Serial.println("Stopped measurements");
}); });
@ -114,6 +130,8 @@ void httpSetup(SessionManager<Session_T> * sessionManager)
if( req->hasParam("startIdx") ) { if( req->hasParam("startIdx") ) {
startIdx = req->getParam("startIdx")->value().toInt(); startIdx = req->getParam("startIdx")->value().toInt();
} }
Serial.print("Data request, start index: ");
Serial.println(startIdx);
StreamingMsgPackEncoder<DummyWriter> encoderToDetermineSize(nullptr); StreamingMsgPackEncoder<DummyWriter> encoderToDetermineSize(nullptr);
encoderToDetermineSize.setSizeCountMode(true); encoderToDetermineSize.setSizeCountMode(true);
@ -122,18 +140,14 @@ void httpSetup(SessionManager<Session_T> * sessionManager)
Serial.print("Sending started of total size "); Serial.print("Sending started of total size ");
Serial.println(totalSize); Serial.println(totalSize);
auto callback = [=](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { auto callback = [=](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
Serial.print("Partial send maxLen ");
Serial.print(maxLen);
Serial.print(" index ");
Serial.println(index);
CopyWriter copyWriter(buffer); CopyWriter copyWriter(buffer);
ChunkedStreamingMsgPackEncoder<CopyWriter> encoder(&copyWriter, index, index + maxLen); ChunkedStreamingMsgPackEncoder<CopyWriter> encoder(&copyWriter, index, index + maxLen);
sessionManager->getSession().serialize(encoder, startIdx); sessionManager->getSession().serialize(encoder, startIdx);
Serial.print("Bytes sent ");
Serial.println(encoder.sentBytes() - index);
return encoder.sentBytes() - index; return encoder.sentBytes() - index;
}; };
AsyncWebServerResponse *response = req->beginResponse("application/x-msgpack", totalSize, callback); AsyncWebServerResponse *response = req->beginResponse("application/x-msgpack", totalSize, callback);
response->addHeader("Access-Control-Allow-Origin", "*");
auto sessionId = sessionManager->getSession().getStartTime(); auto sessionId = sessionManager->getSession().getStartTime();
response->addHeader("content-disposition", "attachment; filename=\"" + String(sessionId) + ".st\""); response->addHeader("content-disposition", "attachment; filename=\"" + String(sessionId) + ".st\"");
req->send(response); req->send(response);
@ -144,6 +158,38 @@ void httpSetup(SessionManager<Session_T> * sessionManager)
server.begin(); server.begin();
} }
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("- failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void setup() void setup()
{ {
// Serial // Serial
@ -153,14 +199,19 @@ void setup()
Serial.println("----- New start -----"); Serial.println("----- New start -----");
// File system // File system
SPIFFS.begin(); bool spiffsResult = SPIFFS.begin(true);
Serial.printf("Spiffs begin %d\n", spiffsResult);
printDeviceInfo(); printDeviceInfo();
// WiFi // WiFi
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD); WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
WiFi.hostname(CONFIG_HOSTNAME); #ifdef USE_ESP32
WiFi.setHostname(CONFIG_HOSTNAME);
#else
WIFI.hostname(CONFIG_HOSTNAME);
#endif
Serial.print(F("\n\n")); Serial.print(F("\n\n"));
Serial.println(F("Waiting for WIFI connection...")); Serial.println(F("Waiting for WIFI connection..."));
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED) {
@ -178,6 +229,9 @@ void setup()
// HTTP & Websocket server // HTTP & Websocket server
httpSetup(&sessionManager); httpSetup(&sessionManager);
Serial.println("Spiffs listing:");
listDir(SPIFFS, "/", 3);
} }
void loop() { void loop() {