Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async control & api update #3

Merged
merged 23 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
aff9e62
Basic impl. with a bugs
GreenWizard2015 Dec 28, 2023
f54a375
would this fix CI?
GreenWizard2015 Dec 28, 2023
c8c2e45
maybe now?
GreenWizard2015 Dec 28, 2023
c6003dc
last try
GreenWizard2015 Dec 28, 2023
815c496
pls?
GreenWizard2015 Dec 28, 2023
54b8e58
remove local and attempt to switch to unity framework
omonrise Dec 29, 2023
0f8ea31
Dependency Unity for testing should not be part of build dependencies…
psmgeelen Dec 29, 2023
5e0bbcf
remove unity from libdeps
omonrise Dec 29, 2023
4d1bab3
Merge branch 'feature/async_control' of https://github.com/psmgeelen/…
omonrise Dec 29, 2023
3288759
fix everything?
GreenWizard2015 Dec 29, 2023
7f01633
default env for platformio build
GreenWizard2015 Dec 29, 2023
6dd0463
configure CI to build only for Android
GreenWizard2015 Dec 29, 2023
7c12ef0
fix
GreenWizard2015 Dec 29, 2023
e2f62b6
fix typo
GreenWizard2015 Dec 29, 2023
7761f46
Separate out CI
psmgeelen Dec 29, 2023
7046cf4
Update user authentication logic
GreenWizard2015 Dec 30, 2023
89347f0
shared_ptr + return error as JSON
GreenWizard2015 Dec 30, 2023
8eb199d
Merge branch 'feature/async_control' of github.com:psmgeelen/projectt…
GreenWizard2015 Dec 30, 2023
63bee21
small rework
GreenWizard2015 Dec 30, 2023
311e314
extracted secrets from main.cpp
GreenWizard2015 Dec 30, 2023
75a7629
fix CI
GreenWizard2015 Dec 30, 2023
267322c
very big update. Reorganized the code, added a command processor, tests.
GreenWizard2015 Dec 30, 2023
eade444
prevent CORS issue...?
GreenWizard2015 Jan 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/platformio_build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: PlatformIO CI - Build for Arduino

on: [push]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: |
~/.cache/pip
~/.platformio/.cache
key: ${{ runner.os }}-pio
- uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Install PlatformIO Core
run: pip install --upgrade platformio

# rename src/secrets.h.example to src/secrets.h, to use a dummy values during build
- name: Copy secrets.h
run: cp ./controller/tea_poor/src/secrets.h.example ./controller/tea_poor/src/secrets.h

- name: Build PlatformIO Project for Arduino
working-directory: ./controller/tea_poor
run: pio run -e uno_r4_wifi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: PlatformIO CI
name: PlatformIO CI - Unit Tests

on: [push]

Expand All @@ -20,6 +20,6 @@ jobs:
- name: Install PlatformIO Core
run: pip install --upgrade platformio

- name: Build PlatformIO Project
- name: Run tests on the native platform
working-directory: ./controller/tea_poor
run: pio run
run: pio test -e native
3 changes: 3 additions & 0 deletions controller/tea_poor/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

# hide secrets
src/secrets.h
15 changes: 15 additions & 0 deletions controller/tea_poor/lib/Arduino/ArduinoEnvironment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Arduino environment
#ifndef ARDUINO_ENVIRONMENT_H
#define ARDUINO_ENVIRONMENT_H

#include <IEnvironment.h>
#include <Arduino.h>

class ArduinoEnvironment : public IEnvironment {
public:
unsigned long time() const override {
return millis();
}
};

#endif // ARDUINO_ENVIRONMENT_H
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,12 @@ void RemoteControl::process() {
_app.process(&client);
client.stop();
}
}

String RemoteControl::asJSONString() const {
String result = "{";
result += "\"SSID\": \"" + _SSID + "\",";
result += "\"signal strength\": " + String(WiFi.RSSI());
result += "}";
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class RemoteControl {
~RemoteControl();
void setup(RemoteControlRoutesCallback routes);
void process();
String asJSONString() const;
private:
const String _SSID;
const String _SSIDPassword;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,17 @@ void WaterPumpController::setup() {
pinMode(_directionPin, OUTPUT);
pinMode(_brakePin, OUTPUT);
pinMode(_powerPin, OUTPUT);
// TODO: check that its okay to do during setup
stopPump();
stop();
}

void WaterPumpController::pour(int milliseconds) {
startPump();
delay(milliseconds);
stopPump();
}

void WaterPumpController::startPump() {
_state = PUMP_ON;
void WaterPumpController::start() {
_isRunning = true;
digitalWrite(_brakePin, LOW); // release breaks
analogWrite(_powerPin, 255);
}

void WaterPumpController::stopPump() {
void WaterPumpController::stop() {
digitalWrite(_brakePin, HIGH); // activate breaks
analogWrite(_powerPin, 0);
_state = PUMP_OFF;
}
_isRunning = false;
}
23 changes: 23 additions & 0 deletions controller/tea_poor/lib/Arduino/WaterPumpController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef WATERPUMPCONTROLLER_H
#define WATERPUMPCONTROLLER_H
#include <IWaterPump.h>

class WaterPumpController: public IWaterPump {
private:
const int _directionPin;
const int _brakePin;
const int _powerPin;
const int _maxPower = 255;
bool _isRunning = false;
public:
WaterPumpController(int directionPin, int brakePin, int powerPin);
virtual ~WaterPumpController() override;

virtual void setup() override;
virtual void start() override;
virtual void stop() override;

virtual bool isRunning() const override { return _isRunning; }
};

#endif
58 changes: 58 additions & 0 deletions controller/tea_poor/lib/CommandProcessor/CommandProcessor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "CommandProcessor.h"
#include <cstring>
#include <sstream>

bool isValidIntNumber(const char *str, const int maxValue, const int minValue=0) {
const int len = strlen(str);
if (len < 1) return false;
// check that string contains only digits
// first character can be '-' for negative numbers
if ((str[0] != '-') && !isdigit(str[0])) return false;
for (int i = 1; i < len; i++) {
if (!isdigit(str[i])) return false;
}
// check that number is in range
const int value = atoi(str);
if (value < minValue) return false;
if (maxValue <= value) return false;
return true;
}

std::string CommandProcessor::status() {
std::stringstream response;
response << "{";
// send water threshold
response << "\"water threshold\": " << _waterPumpSafeThreshold << ", ";
// send water pump status
const auto waterPumpStatus = _waterPump->status();
const auto now = _env->time();
const auto timeLeft = waterPumpStatus.isRunning ? waterPumpStatus.stopTime - now : 0;
response
<< "\"pump\": {"
<< " \"running\": " << (waterPumpStatus.isRunning ? "true, " : "false, ")
<< " \"time left\": " << timeLeft
<< "}";
// end of water pump status
///////////////////////////////////
// send remote control status
// response << "\"remote control\": " << remoteControl.asJSONString();
// end of JSON
response << "}";

return response.str();
}

std::string CommandProcessor::pour_tea(const char *milliseconds) {
if (!isValidIntNumber(milliseconds, _waterPumpSafeThreshold)) {
// send error message as JSON
return std::string("{ \"error\": \"invalid milliseconds value\" }");
}
// start pouring tea
_waterPump->start( atoi(milliseconds), _env->time() );
return status();
}

std::string CommandProcessor::stop() {
_waterPump->stop();
return status();
}
30 changes: 30 additions & 0 deletions controller/tea_poor/lib/CommandProcessor/CommandProcessor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// CommandProcessor class definition
#ifndef COMMANDPROCESSOR_H
#define COMMANDPROCESSOR_H

#include <string>
#include <IWaterPumpSchedulerAPI.h>
#include <IEnvironment.h>

// This class is used to process incoming commands
class CommandProcessor {
public:
CommandProcessor(
int waterPumpSafeThreshold,
const IEnvironmentPtr env,
const IWaterPumpSchedulerAPIPtr waterPump
) :
_waterPumpSafeThreshold(waterPumpSafeThreshold),
_env(env),
_waterPump(waterPump)
{}

std::string status();
std::string pour_tea(const char *milliseconds);
std::string stop();
private:
const int _waterPumpSafeThreshold;
const IEnvironmentPtr _env;
const IWaterPumpSchedulerAPIPtr _waterPump;
};
#endif // COMMANDPROCESSOR_H
28 changes: 0 additions & 28 deletions controller/tea_poor/lib/WaterPumpController/WaterPumpController.h

This file was deleted.

34 changes: 34 additions & 0 deletions controller/tea_poor/lib/WaterPumpScheduler/WaterPumpScheduler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "WaterPumpScheduler.h"

WaterPumpScheduler::WaterPumpScheduler(IWaterPumpPtr waterPump, unsigned long forceStopIntervalMs) :
_waterPump(waterPump),
_forceStopIntervalMs(forceStopIntervalMs)
{
}

WaterPumpScheduler::~WaterPumpScheduler() {}

void WaterPumpScheduler::setup() {
_waterPump->setup();
}

void WaterPumpScheduler::start(unsigned long runTimeMs, unsigned long currentTimeMs) {
_stopTime = currentTimeMs + runTimeMs;
_waterPump->start();
}

void WaterPumpScheduler::stop() {
_waterPump->stop();
_stopTime = 0; // a bit of paranoia :)
}

void WaterPumpScheduler::tick(unsigned long currentTimeMs) {
if (_stopTime <= currentTimeMs) {
stop();
_stopTime = currentTimeMs + _forceStopIntervalMs; // force stop after X milliseconds
}
}

WaterPumpStatus WaterPumpScheduler::status() {
return WaterPumpStatus(_waterPump->isRunning(), _stopTime);
}
30 changes: 30 additions & 0 deletions controller/tea_poor/lib/WaterPumpScheduler/WaterPumpScheduler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef WATERPUMPSCHEDULER_H
#define WATERPUMPSCHEDULER_H

#include <IWaterPump.h>
#include <IWaterPumpSchedulerAPI.h>

// This class is responsible for scheduling water pump
// It is used to make sure that water pump is running for a limited time
// It is also ensuring that water pump is stopped if not needed
class WaterPumpScheduler : public IWaterPumpSchedulerAPI {
private:
IWaterPumpPtr _waterPump;
unsigned long _stopTime = 0;
// each X milliseconds will force stop water pump
unsigned long _forceStopIntervalMs;
public:
WaterPumpScheduler(IWaterPumpPtr waterPump, unsigned long forceStopIntervalMs);
WaterPumpScheduler(IWaterPumpPtr waterPump) : WaterPumpScheduler(waterPump, 1000) {}
~WaterPumpScheduler();

void setup();
// for simplicity and testability we are passing current time as parameter
void tick(unsigned long currentTimeMs);

// Public API
void start(unsigned long runTimeMs, unsigned long currentTimeMs) override;
void stop() override;
WaterPumpStatus status() override;
};
#endif
13 changes: 13 additions & 0 deletions controller/tea_poor/lib/interfaces/IEnvironment.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef IENVIRONMENT_H
#define IENVIRONMENT_H

#include <memory>

class IEnvironment {
public:
virtual unsigned long time() const = 0;
virtual ~IEnvironment() {}
};

typedef std::shared_ptr<IEnvironment> IEnvironmentPtr;
#endif // IENVIRONMENT_H
19 changes: 19 additions & 0 deletions controller/tea_poor/lib/interfaces/IWaterPump.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef IWATERPUMP_H
#define IWATERPUMP_H

#include <memory>

class IWaterPump {
public:
virtual ~IWaterPump() {}

virtual void setup() = 0;
virtual void start() = 0;
virtual void stop() = 0;

virtual bool isRunning() const = 0;
};

// define shared pointer alias
using IWaterPumpPtr = std::shared_ptr<IWaterPump>;
#endif
Loading