Added time trigger settings and corresponding API
Fixed #9: Changing individual step with startTime can fail
This commit is contained in:
parent
381a77e9ce
commit
f220f1b7a1
7
API.md
7
API.md
@ -6,7 +6,8 @@
|
||||
- [POST /api/connection](#post-apiconnection)
|
||||
- [GET /api/steps](#get-apisteps)
|
||||
- [POST /api/steps](#post-apisteps)
|
||||
- [GET /api/geocode/latlong](#get-apigeocodelatlong)
|
||||
- [GET /api/triggers/time](#get-apitriggerstime)
|
||||
- [POST /api/triggers/time](#post-apitriggerstime)
|
||||
- [POST /api/firmware](#post-apifirmware)
|
||||
|
||||
## GET /api/version
|
||||
@ -117,6 +118,10 @@ An optional array 'startTime' can be included which specifies the delay, for eac
|
||||
}
|
||||
```
|
||||
|
||||
## GET /api/triggers/time
|
||||
|
||||
## POST /api/triggers/time
|
||||
|
||||
## POST /api/firmware
|
||||
|
||||
Uploads new firmware. The bin file should be posted as a multipart/form-data file attachment. Name is not relevant.
|
@ -8,5 +8,18 @@
|
||||
],
|
||||
"completions":[
|
||||
["t", "{{ \\$t('${1:}') }}"]
|
||||
]
|
||||
],
|
||||
"settings": {
|
||||
"todoreview": {
|
||||
"exclude_folders": [
|
||||
"*.pioenvs*",
|
||||
"*.piolibdeps*",
|
||||
"*bin*",
|
||||
"*node_modules*"
|
||||
],
|
||||
"patterns": {
|
||||
"TODO": "TODO[\\s]*(?P<todo>.*)$",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,10 @@
|
||||
const uint8_t VersionMajor = 2;
|
||||
const uint8_t VersionMinor = 0;
|
||||
const uint8_t VersionPatch = 0;
|
||||
const uint8_t VersionMetadata = 11;
|
||||
const uint8_t VersionMetadata = 13;
|
||||
const char VersionBranch[] = "release/2.0";
|
||||
const char VersionSemVer[] = "2.0.0-beta.1";
|
||||
const char VersionFullSemVer[] = "2.0.0-beta.1+11";
|
||||
const char VersionCommitDate[] = "2018-01-08";
|
||||
const char VersionFullSemVer[] = "2.0.0-beta.1+13";
|
||||
const char VersionCommitDate[] = "2018-01-10";
|
||||
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@ static const uint32_t SerialDebugStartupDelay = 2000;
|
||||
static const char* ConnectionSettingsFile = "/connection.json";
|
||||
static const char* SystemSettingsFile = "/system.json";
|
||||
static const char* StepSettingsFile = "/stepsettings.dat";
|
||||
static const char* TimeTriggerSettingsFile = "/timetriggersettings.dat";
|
||||
|
||||
|
||||
static const char* DefaultAPSSIDPrefix = "Stairs-";
|
||||
|
@ -15,6 +15,9 @@ bool systemSettingsChanged = false;
|
||||
StepsSettings* stepsSettings = new StepsSettings();
|
||||
bool stepsSettingsChanged = false;
|
||||
|
||||
TimeTriggerSettings* timeTriggerSettings = new TimeTriggerSettings();
|
||||
bool timeTriggerSettingsChanged = false;
|
||||
|
||||
|
||||
Stairs* stairs;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "settings/connection.h"
|
||||
#include "settings/system.h"
|
||||
#include "settings/steps.h"
|
||||
#include "settings/triggers/time.h"
|
||||
#include "stairs.h"
|
||||
|
||||
extern ConnectionSettings* connectionSettings;
|
||||
@ -24,6 +25,10 @@ extern bool systemSettingsChanged;
|
||||
extern StepsSettings* stepsSettings;
|
||||
extern bool stepsSettingsChanged;
|
||||
|
||||
extern TimeTriggerSettings* timeTriggerSettings;
|
||||
extern bool timeTriggerSettingsChanged;
|
||||
|
||||
|
||||
extern Stairs* stairs;
|
||||
|
||||
extern bool shouldReboot;
|
||||
|
@ -85,6 +85,7 @@ void setup()
|
||||
connectionSettings->read();
|
||||
systemSettings->read();
|
||||
stepsSettings->read();
|
||||
timeTriggerSettings->read();
|
||||
|
||||
pinMode(systemSettings->pinAPButton(), INPUT_PULLUP);
|
||||
pinMode(systemSettings->pinLEDAP(), OUTPUT);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../debug.h"
|
||||
#include "../global.h"
|
||||
#include "../settings/connection.h"
|
||||
#include "../settings/triggers/time.h"
|
||||
|
||||
|
||||
void handleGetSteps(AsyncWebServerRequest *request)
|
||||
@ -64,8 +65,86 @@ void handlePostSteps(AsyncWebServerRequest *request, uint8_t *data, size_t len,
|
||||
}
|
||||
|
||||
|
||||
void handleGetTimeTriggers(AsyncWebServerRequest *request)
|
||||
{
|
||||
_dln("API :: get time triggers");
|
||||
|
||||
uint8_t count = timeTriggerSettings->triggerCount();
|
||||
|
||||
DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(count) + JSON_OBJECT_SIZE(2) + count*JSON_OBJECT_SIZE(5));
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
root["transitionTime"] = timeTriggerSettings->transitionTime();
|
||||
|
||||
JsonArray& jsonTriggers = root.createNestedArray("triggers");
|
||||
|
||||
for (uint8_t i = 0; i < count; i++)
|
||||
{
|
||||
TimeTrigger* trigger = timeTriggerSettings->trigger(i);
|
||||
|
||||
JsonObject& jsonTrigger = jsonTriggers.createNestedObject();
|
||||
jsonTrigger["timeofDay"] = trigger->timeOfDay;
|
||||
jsonTrigger["daysOfWeek"] = trigger->daysOfWeek;
|
||||
jsonTrigger["brightness"] = trigger->brightness;
|
||||
jsonTrigger["triggerType"] = (uint8_t)trigger->triggerType;
|
||||
jsonTrigger["enabled"] = trigger->enabled;
|
||||
}
|
||||
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
root.printTo(*response);
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
|
||||
void handlePostTimeTriggers(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
|
||||
{
|
||||
_dln("API :: post time triggers");
|
||||
|
||||
DynamicJsonBuffer jsonBuffer(JSON_ARRAY_SIZE(10) + JSON_OBJECT_SIZE(2) + 10*JSON_OBJECT_SIZE(5) + 510);
|
||||
JsonObject& root = jsonBuffer.parseObject((char*)data);
|
||||
if (!root.success())
|
||||
{
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonArray& jsonTriggers = root["triggers"];
|
||||
if (jsonTriggers.size() > 255)
|
||||
{
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
timeTriggerSettings->transitionTime(root["transitionTime"]);
|
||||
timeTriggerSettings->beginSetTriggers(jsonTriggers.size());
|
||||
|
||||
TimeTrigger trigger;
|
||||
for (uint8_t i = 0; i < jsonTriggers.size(); i++)
|
||||
{
|
||||
JsonObject& jsonTrigger = jsonTriggers[i];
|
||||
|
||||
trigger.timeOfDay = jsonTrigger["timeOfDay"];
|
||||
trigger.daysOfWeek = jsonTrigger["daysOfWeek"];
|
||||
trigger.brightness = jsonTrigger["brightness"];
|
||||
trigger.triggerType = (TimeTriggerType)(uint8_t)jsonTrigger["triggerType"];
|
||||
trigger.enabled = jsonTrigger["enabled"];
|
||||
|
||||
timeTriggerSettings->setTrigger(i, &trigger);
|
||||
}
|
||||
|
||||
timeTriggerSettings->endSetTriggers();
|
||||
timeTriggerSettings->write();
|
||||
timeTriggerSettingsChanged = true;
|
||||
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
|
||||
void registerAPIRoutes(AsyncWebServer* server)
|
||||
{
|
||||
server->on("/api/steps", HTTP_GET, handleGetSteps);
|
||||
server->on("/api/steps", HTTP_POST, devNullRequest, devNullFileUpload, handlePostSteps);
|
||||
|
||||
server->on("/api/triggers/time", HTTP_GET, handleGetTimeTriggers);
|
||||
server->on("/api/triggers/time", HTTP_POST, devNullRequest, devNullFileUpload, handlePostTimeTriggers);
|
||||
}
|
@ -27,6 +27,10 @@ class SystemSettings : CharProperties
|
||||
|
||||
char* mMapsAPIKey = nullptr;
|
||||
|
||||
// TODO loginRequired
|
||||
// TODO loginUsername
|
||||
// TODO loginPassword
|
||||
|
||||
public:
|
||||
void read();
|
||||
void write();
|
||||
|
148
src/settings/triggers/time.cpp
Normal file
148
src/settings/triggers/time.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Stairs
|
||||
* Copyright 2017 (c) Mark van Renswoude
|
||||
*
|
||||
* https://git.x2software.net/pub/Stairs
|
||||
*/
|
||||
#include "time.h"
|
||||
#include <string.h>
|
||||
#include <FS.h>
|
||||
#include "../../debug.h"
|
||||
|
||||
|
||||
timeDayOfWeek_t toTimeDayOfWeek(DayOfWeek day)
|
||||
{
|
||||
switch (day)
|
||||
{
|
||||
case Monday: return dowMonday;
|
||||
case Tuesday: return dowTuesday;
|
||||
case Wednesday: return dowWednesday;
|
||||
case Thursday: return dowThursday;
|
||||
case Friday: return dowFriday;
|
||||
case Saturday: return dowSaturday;
|
||||
case Sunday: return dowSunday;
|
||||
}
|
||||
|
||||
return dowInvalid;
|
||||
}
|
||||
|
||||
|
||||
DayOfWeek toDayOfWeek(timeDayOfWeek_t timeDay)
|
||||
{
|
||||
switch (timeDay)
|
||||
{
|
||||
case dowSunday: return Sunday;
|
||||
case dowMonday: return Monday;
|
||||
case dowTuesday: return Tuesday;
|
||||
case dowWednesday: return Wednesday;
|
||||
case dowThursday: return Thursday;
|
||||
case dowFriday: return Friday;
|
||||
case dowSaturday: return Saturday;
|
||||
}
|
||||
|
||||
return Monday;
|
||||
}
|
||||
|
||||
|
||||
struct Header
|
||||
{
|
||||
uint8_t version;
|
||||
uint8_t triggerCount;
|
||||
uint16_t transitionTime;
|
||||
};
|
||||
|
||||
|
||||
void TimeTriggerSettings::read()
|
||||
{
|
||||
_dln("TimeTriggerSettings :: Loading time triggers");
|
||||
File f = SPIFFS.open(TimeTriggerSettingsFile, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
if (!f.available())
|
||||
return;
|
||||
|
||||
Header header;
|
||||
f.readBytes((char*)&header, sizeof(Header));
|
||||
|
||||
if (header.version != 1)
|
||||
return;
|
||||
|
||||
mTransitionTime = header.transitionTime;
|
||||
beginSetTriggers(header.triggerCount);
|
||||
|
||||
if (header.triggerCount > 0)
|
||||
f.readBytes((char*)&mTriggers, header.triggerCount * sizeof(TimeTrigger));
|
||||
|
||||
endSetTriggers();
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
||||
void TimeTriggerSettings::write()
|
||||
{
|
||||
_dln("TimeTriggerSettings :: Saving time triggers");
|
||||
File f = SPIFFS.open(TimeTriggerSettingsFile, "w");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
Header header;
|
||||
header.version = 1;
|
||||
header.transitionTime = mTransitionTime;
|
||||
header.triggerCount = mTriggerCount;
|
||||
|
||||
f.write((uint8_t*)&header, sizeof(Header));
|
||||
f.write((uint8_t*)&mTriggers, header.triggerCount * sizeof(TimeTrigger));
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
||||
void TimeTriggerSettings::beginSetTriggers(uint8_t count)
|
||||
{
|
||||
if (mTriggers != nullptr)
|
||||
delete [] mTriggers;
|
||||
|
||||
mTriggers = new TimeTrigger[count];
|
||||
mTriggerCount = count;
|
||||
}
|
||||
|
||||
|
||||
void TimeTriggerSettings::setTrigger(uint8_t index, TimeTrigger* value)
|
||||
{
|
||||
memcpy(&mTriggers[index], value, sizeof(TimeTrigger));
|
||||
}
|
||||
|
||||
|
||||
void TimeTriggerSettings::endSetTriggers()
|
||||
{
|
||||
// Sort triggers by time of day
|
||||
// Based on the Comb sort implementation by Rob Tillaart
|
||||
// http://forum.arduino.cc/index.php?topic=280486.0
|
||||
uint8_t i, j;
|
||||
uint8_t gap;
|
||||
bool swapped = true;
|
||||
TimeTrigger temp;
|
||||
|
||||
gap = mTriggerCount;
|
||||
while (gap > 1 || swapped)
|
||||
{
|
||||
if (gap > 1)
|
||||
{
|
||||
gap = gap * 10/13;
|
||||
if (gap == 9 || gap == 10) gap = 11;
|
||||
}
|
||||
|
||||
swapped = false;
|
||||
for (i = 0, j = gap; j < mTriggerCount; i++, j++)
|
||||
{
|
||||
if (mTriggers[i].timeOfDay > mTriggers[j].timeOfDay)
|
||||
{
|
||||
temp = mTriggers[i];
|
||||
mTriggers[i] = mTriggers[j];
|
||||
mTriggers[j] = temp;
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
68
src/settings/triggers/time.h
Normal file
68
src/settings/triggers/time.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Stairs
|
||||
* Copyright 2017 (c) Mark van Renswoude
|
||||
*
|
||||
* https://git.x2software.net/pub/Stairs
|
||||
*/
|
||||
#ifndef __settingstriggerstime
|
||||
#define __settingstriggerstime
|
||||
|
||||
#include <TimeLib.h>
|
||||
|
||||
enum DayOfWeek
|
||||
{
|
||||
Monday = 1,
|
||||
Tuesday = 2,
|
||||
Wednesday = 4,
|
||||
Thursday = 8,
|
||||
Friday = 16,
|
||||
Saturday = 32,
|
||||
Sunday = 64
|
||||
};
|
||||
|
||||
|
||||
extern timeDayOfWeek_t toTimeDayOfWeek(DayOfWeek day);
|
||||
extern DayOfWeek toDayOfWeek(timeDayOfWeek_t timeDay);
|
||||
|
||||
|
||||
enum TimeTriggerType
|
||||
{
|
||||
FixedTime = 0,
|
||||
RelativeToSunrise = 1,
|
||||
RelativeToSunset = 2
|
||||
};
|
||||
|
||||
|
||||
struct TimeTrigger
|
||||
{
|
||||
uint16_t timeOfDay;
|
||||
uint8_t daysOfWeek;
|
||||
uint8_t brightness;
|
||||
TimeTriggerType triggerType;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
|
||||
class TimeTriggerSettings
|
||||
{
|
||||
private:
|
||||
uint16_t mTransitionTime = 0;
|
||||
uint8_t mTriggerCount = 0;
|
||||
TimeTrigger* mTriggers = nullptr;
|
||||
|
||||
public:
|
||||
void read();
|
||||
void write();
|
||||
|
||||
uint16_t transitionTime() { return mTransitionTime; }
|
||||
void transitionTime(uint16_t value) { mTransitionTime = value; }
|
||||
|
||||
uint8_t triggerCount() { return mTriggerCount; }
|
||||
TimeTrigger* trigger(uint8_t index) { return &mTriggers[index]; }
|
||||
|
||||
void beginSetTriggers(uint8_t count);
|
||||
void setTrigger(uint8_t index, TimeTrigger* value);
|
||||
void endSetTriggers();
|
||||
};
|
||||
|
||||
#endif
|
@ -105,6 +105,8 @@ void Stairs::tick()
|
||||
|
||||
applyCurrentValue(step);
|
||||
}
|
||||
else
|
||||
mTick = true;
|
||||
}
|
||||
else if (elapsedTime >= stepState->remainingTime)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user