added json, more pump code, bugs

This commit is contained in:
2023-04-14 20:39:11 +02:00
parent 08f14424af
commit d22e0bc752
10 changed files with 322 additions and 55 deletions
+2
View File
@@ -1,5 +1,7 @@
{ {
"cSpell.words": [ "cSpell.words": [
"Huus",
"Lebennig",
"RCLK", "RCLK",
"SRCLK", "SRCLK",
"SROE", "SROE",
+2 -1
View File
@@ -14,4 +14,5 @@
#define INT_HALL_PIN 2 #define INT_HALL_PIN 2
#define VALVE_COUNT 12 #define VALVE_COUNT 12
const uint8_t valvePins[VALVE_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; const uint8_t valvePins[VALVE_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
const char mainTopic[] = "LebennigHuus/Garden/Irrigation";
+15
View File
@@ -0,0 +1,15 @@
{
"pump": {
"status": 1,
"duration": 12,
"pressure": 12.5,
"flow": 120
}
}
{
"pump": {
"mode": 1,
"duration": 25
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"valve": {
"duration": 2,
"number": 3
}
}
+156 -30
View File
@@ -1,74 +1,62 @@
#include "pump.h" #include "pump.h"
Pump::Pump(uint8_t pumpPin, uint8_t pressurePin, uint8_t flowPin, uint8_t errorLedPin) { Pump::Pump(uint8_t pumpPin, uint8_t pressurePin, uint8_t flowPin, uint8_t ledPin) {
this->pumpPin = pumpPin; this->pumpPin = pumpPin;
this->pressurePin = pressurePin; this->pressurePin = pressurePin;
this->flowPin = flowPin; this->flowPin = flowPin;
this->errorLedPin = errorLedPin; this->ledPin = ledPin;
pinMode(this->pumpPin, OUTPUT); pinMode(this->pumpPin, OUTPUT);
pinMode(this->errorLedPin, OUTPUT); pinMode(this->ledPin, OUTPUT);
pinMode(this->pressurePin, INPUT); pinMode(this->pressurePin, INPUT);
// Hall flow sensor? // Hall flow sensor?
digitalWrite(this->pumpPin, LOW); digitalWrite(this->pumpPin, LOW);
digitalWrite(this->errorLedPin, LOW); digitalWrite(this->ledPin, LOW);
} }
void Pump::loop() { void Pump::loop() {
switch (this->state) { switch (this->state) {
case State::Off : case State::Off :
break; break;
case State::On : case State::On :
this->timerStandby = false;
this->checkSensors();
break; break;
case State::Timer : case State::Timer :
this->stateTimer();
break; break;
case State::Standby : case State::Standby :
this->stateStandby();
break; break;
case State::Error : case State::Error :
if (millis() - this->startTime > Pump::blinkTime) { this->stateError();
this->startTime = millis();
if (this->ledState) {
this->ledState = false;
digitalWrite(this->errorLedPin, LOW);
} else {
this->ledState = true;
digitalWrite(this->errorLedPin, HIGH);
}
}
break;
default:
break; break;
} }
} }
void Pump::activate(uint32_t duration) { void Pump::activate(uint32_t duration) {
this->startTime = millis();
if (duration) { if (duration) {
this->state = State::Timer; this->changeState(State::Timer);
this->duration = duration; this->duration = duration;
} else { } else {
this->state = State::On; this->changeState(State::On);
} }
} }
void Pump::stop() { void Pump::stop() {
if (this->state != State::Error) this->changeState(State::Off);
this->state = State::Off;
} }
void Pump::clearError() { void Pump::clearError() {
if (this->state == State::Error) if (this->state == State::Error) {
this->state = State::Off; this->state = State::Off;
this->changeState(State::Off);
}
} }
uint16_t Pump::getPressure() { uint16_t Pump::getPressure() {
@@ -76,13 +64,151 @@ uint16_t Pump::getPressure() {
} }
uint32_t Pump::getRunningTime() { uint32_t Pump::getRunningTime() {
return millis() -this->startTime; if (this->state == State::Off)
return 0;
return (millis() - this->startTime) / 1000;
} }
uint16_t Pump::getFlow() { uint16_t Pump::getFlow() {
return 0; return 0;
} }
void Pump::checkSensors() { uint16_t Pump::getStatus() {
switch (this->state) {
case State::Off :
return 0;
break;
case State::On :
return 1;
break;
case State::Timer :
return 2;
break;
case State::Standby :
return 3;
break;
case State::Error :
return -1;
break;
default:
return -2;
break;
}
}
bool Pump::checkSensors() {
if (millis() - this->lastMillisCheckSensor < Pump::delayCheckSensor)
return;
this->lastMillisCheckSensor = millis();
} //TODO: read pressure
//TODO: read flow
if (this->flow) {
return true;
}
if (!this->pressure) {
this->changeState(State::Error);
return false;
}
if (pressure > Pump::maxPressure) {
if (this->maxPressureStart == 0)
this->maxPressureStart = millis();
else if (millis() - this->maxPressureStart > Pump::maxMaxPressureTime)
this->changeState(State::Standby);
}
return true;
}
void Pump::handlePins(bool state) {
digitalWrite(this->pumpPin, state);
digitalWrite(this->ledPin, state);
if (state) {
this->timerStandby = false;
this->startTime = millis();
this->maxPressureStart = 0;
}
}
void Pump::changeState(State state) {
if (this->state == State::Error)
return;
if (this->state == state)
return;
switch (state) {
case State::Off :
this->handlePins(false);
this->pressure = 0;
this->flow = 0;
break;
case State::On :
this->handlePins(true);
break;
case State::Timer :
this->handlePins(true);
break;
case State::Standby :
if (this->state == State::Timer)
this->timerStandby = true;
this->handlePins(false);
break;
case State::Error :
this->handlePins(false);
break;
default:
break;
}
this->state = state;
}
void Pump::stateTimer() {
if (!this->checkSensors())
return;
if (millis() - this->lastMillisTimer < Pump::delayTimer)
return;
this->lastMillisTimer = millis();
uint8_t minutesOn = (millis() - this->startTime) / 1000 / 60;
if (minutesOn >= this->duration)
this->changeState(State::Off);
}
void Pump::stateStandby() {
this->checkSensors();
if (this->pressure < Pump::maxPressure / 2) {
if (this->timerStandby)
this->changeState(State::Timer);
else
this->changeState(State::On);
}
}
void Pump::stateError() {
if (millis() - this->startTime > Pump::blinkTime) {
this->startTime = millis();
if (this->ledState) {
this->ledState = false;
digitalWrite(this->ledPin, LOW);
} else {
this->ledState = true;
digitalWrite(this->ledPin, HIGH);
}
}
}
+23 -4
View File
@@ -4,7 +4,6 @@
class Pump { class Pump {
public: public:
static const uint16_t blinkTime = 1000;
enum State { enum State {
Off, Off,
On, On,
@@ -13,7 +12,7 @@ class Pump {
Error Error
}; };
Pump(uint8_t pumpPin, uint8_t pressurePin, uint8_t flowPin, uint8_t errorLedPin); Pump(uint8_t pumpPin, uint8_t pressurePin, uint8_t flowPin, uint8_t ledPin);
void loop(); void loop();
@@ -24,20 +23,40 @@ class Pump {
uint16_t getPressure(); uint16_t getPressure();
uint32_t getRunningTime(); uint32_t getRunningTime();
uint16_t getFlow(); uint16_t getFlow();
uint16_t getStatus();
State getState() { return this->state; } State getState() { return this->state; }
private: private:
void checkSensors(); static const uint8_t delayCheckSensor = 50;
static const uint16_t blinkTime = 1000;
static const uint16_t maxPressure = 1000;
static const uint16_t maxMaxPressureTime = 30000;
static const uint16_t delayTimer = 1000;
bool checkSensors();
void handlePins(bool state);
void changeState(State state);
void stateTimer();
void stateStandby();
void stateError();
State state = State::Off; State state = State::Off;
bool ledState = false; bool ledState = false;
bool timerStandby = false;
uint8_t pumpPin; uint8_t pumpPin;
uint8_t pressurePin; uint8_t pressurePin;
uint8_t flowPin; uint8_t flowPin;
uint8_t errorLedPin; uint8_t ledPin;
uint16_t delayTimer = 1000;
uint16_t flow;
uint16_t pressure;
uint32_t startTime; uint32_t startTime;
uint32_t duration; uint32_t duration;
uint32_t lastMillisTimer = 0;
uint32_t lastMillisCheckSensor = 0;
uint32_t maxPressureStart = 0;
}; };
+15 -7
View File
@@ -10,7 +10,9 @@ void Valve::loop() {
this->loopLastMillis = millis(); this->loopLastMillis = millis();
for (uint8_t i = 0; i < this->valveCount; i++) { for (uint8_t i = 0; i < this->valveCount; i++) {
uint8_t minutesOn = (millis() - this->valves[i].startTime) / 1000; if (this->valves[i].duration == 0)
continue;
uint8_t minutesOn = (millis() - this->valves[i].startTime) / 1000 / 60;
if (minutesOn >= this->valves[i].duration) if (minutesOn >= this->valves[i].duration)
this->close(i); this->close(i);
} }
@@ -38,6 +40,9 @@ void Valve::open(uint8_t valveNumber, uint8_t minutes) {
this->valves[valveNumber].duration = minutes; this->valves[valveNumber].duration = minutes;
this->valves[valveNumber].startTime = millis(); this->valves[valveNumber].startTime = millis();
this->setValve(valveNumber, true); this->setValve(valveNumber, true);
Serial.print(F("Opened valve: "));
Serial.println(valveNumber);
} }
void Valve::close(uint8_t valveNumber) { void Valve::close(uint8_t valveNumber) {
@@ -46,13 +51,13 @@ void Valve::close(uint8_t valveNumber) {
this->valves[valveNumber].duration = 0; this->valves[valveNumber].duration = 0;
this->setValve(valveNumber, false); this->setValve(valveNumber, false);
Serial.print(F("Closed valve: "));
Serial.println(valveNumber);
} }
void Valve::closeAll() { void Valve::closeAll() {
for (uint8_t i = 0; i < this->valveCount; i++) { for (uint8_t i = 0; i < this->valveCount; i++)
this->valves[i].duration = 0; this->close(i);
this->setValve(i, false);
}
} }
uint8_t Valve::getNumOfOpen() { uint8_t Valve::getNumOfOpen() {
@@ -63,12 +68,15 @@ uint8_t Valve::getNumOfOpen() {
return res; return res;
} }
uint8_t Valve::getTimeLeft(uint8_t valveNumber) { uint16_t Valve::getTimeLeft(uint8_t valveNumber) {
if (valveNumber >= this->valveCount) if (valveNumber >= this->valveCount)
return -1; return -1;
if (this->valves[valveNumber].duration == 0)
return 0;
uint32_t millisOn = millis() - this->valves[valveNumber].startTime; uint32_t millisOn = millis() - this->valves[valveNumber].startTime;
return this->valves[valveNumber].duration - (millisOn / 1000); return this->valves[valveNumber].duration * 60 - (millisOn / 1000);
} }
void Valve::setValve(uint8_t valveNumber, bool state) { void Valve::setValve(uint8_t valveNumber, bool state) {
+1 -2
View File
@@ -25,8 +25,7 @@ class Valve {
void closeAll(); void closeAll();
uint8_t getNumOfOpen(); uint8_t getNumOfOpen();
uint8_t getTimeLeft(uint8_t valveNumber); uint16_t getTimeLeft(uint8_t valveNumber);
private: private:
void setValve(uint8_t valveNumber, bool state); void setValve(uint8_t valveNumber, bool state);
+1
View File
@@ -17,3 +17,4 @@ lib_deps =
arduino-libraries/Ethernet@^2.0.1 arduino-libraries/Ethernet@^2.0.1
https://git.kleiax.de/PlatformIO-Libs/Shiftregister.git#v1.0 https://git.kleiax.de/PlatformIO-Libs/Shiftregister.git#v1.0
knolleary/PubSubClient@^2.8 knolleary/PubSubClient@^2.8
bblanchon/ArduinoJson@^6.21.2
+101 -11
View File
@@ -4,13 +4,12 @@
#include <PubSubClient.h> #include <PubSubClient.h>
#include <shiftregister.h> #include <shiftregister.h>
#include <string.h> #include <string.h>
#include <ArduinoJson.h>
#include "config.h" #include "config.h"
#include "pump.h" #include "pump.h"
#include "valve.h" #include "valve.h"
#define COUNT_HTTP_METHOD 3
#define METHOD_LENGTH 6
#define BUFFER_SIZE 128 #define BUFFER_SIZE 128
byte mac[] = { 0xC3, 0xF9, 0x7C, 0xB1, 0x8C, 0xF3 }; byte mac[] = { 0xC3, 0xF9, 0x7C, 0xB1, 0x8C, 0xF3 };
@@ -34,10 +33,13 @@ PubSubClient client(ethClient);
void reconnect(); void reconnect();
void callback(char* topic, byte* payload, unsigned int length); void callback(char* topic, byte* payload, unsigned int length);
void sendPumpStatus();
void sendValveStatus(uint8_t valveNumber);
void sendInfo();
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
Serial.println("Arduino Irrigation"); Serial.println(F("Arduino Irrigation"));
valves.addShiftRegister(&reg); valves.addShiftRegister(&reg);
for (uint8_t i = 0; i < VALVE_COUNT; i++) for (uint8_t i = 0; i < VALVE_COUNT; i++)
@@ -58,25 +60,70 @@ void loop() {
reconnect(); reconnect();
client.loop(); client.loop();
pump.loop(); pump.loop();
valves.loop();
static uint32_t lastDataSend = 0;
if (millis() - lastDataSend > 2000) {
sendInfo();
sendPumpStatus();
for (uint8_t i = 0; i < VALVE_COUNT; i++)
sendValveStatus(i);
lastDataSend = millis();
}
} }
void callback(char* topic, byte* payload, unsigned int length) { void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived ["); if (length > 128) {
Serial.print(topic); Serial.println(F("Payload to big."));
Serial.print("] "); return;
for (unsigned int i=0;i<length;i++) {
Serial.print((char)payload[i]);
} }
Serial.println();
StaticJsonDocument<128> doc;
DeserializationError error = deserializeJson(doc, payload, length);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
if (doc.containsKey("valve")) {
uint8_t valveNumber = doc["valve"]["number"];
uint8_t duration = doc["valve"]["duration"];
if (duration)
valves.open(valveNumber, duration);
else
valves.close(valveNumber);
} else if (doc.containsKey("pump")) {
uint8_t mode = doc["pump"]["mode"];
uint8_t duration = doc["pump"]["duration"];
if (mode)
pump.activate(duration);
else
pump.stop();
} else {
Serial.println(F("Key not found."));
}
// Serial.print("Message arrived [");
// Serial.print(topic);
// Serial.print("] ");
// for (uint8_t i=0;i<length;i++) {
// Serial.print((char)payload[i]);
// }
// Serial.println();
} }
void reconnect() { void reconnect() {
char topic[64];
while (!client.connected()) { while (!client.connected()) {
Serial.print("Attempting MQTT connection..."); Serial.print("Attempting MQTT connection...");
if (client.connect("arduinoClient")) { if (client.connect("arduinoClient")) {
Serial.println("connected"); Serial.println("connected");
client.publish("outTopic","reconnect"); sprintf(topic, "%s/info", mainTopic);
client.subscribe("inTopic"); client.publish(topic,"reconnect");
sprintf(topic, "%s/order", mainTopic);
client.subscribe(topic);
} else { } else {
Serial.print("failed, rc="); Serial.print("failed, rc=");
Serial.print(client.state()); Serial.print(client.state());
@@ -85,3 +132,46 @@ void reconnect() {
} }
} }
} }
void sendPumpStatus() {
StaticJsonDocument<96> doc;
JsonObject pumpJson = doc.createNestedObject("pump");
pumpJson["status"] = pump.getStatus();
pumpJson["duration"] = pump.getRunningTime();
pumpJson["pressure"] = pump.getPressure();
pumpJson["flow"] = pump.getFlow();
char buffer[256];
char topic[64];
sprintf(topic, "%s/pump", mainTopic);
size_t n = serializeJson(doc, buffer);
client.publish(topic, buffer, n);
}
void sendValveStatus(uint8_t valveNumber) {
StaticJsonDocument<96> doc;
JsonObject valve = doc.createNestedObject("valve");
valve["timeLeft"] = valves.getTimeLeft(valveNumber);
char buffer[256];
char topic[64];
sprintf(topic, "%s/valve_%d", mainTopic, valveNumber);
size_t n = serializeJson(doc, buffer);
client.publish(topic, buffer, n);
}
void sendInfo() {
StaticJsonDocument<48> doc;
JsonObject info = doc.createNestedObject("valve");
info["uptime"] = millis() / 1000;
info["opened"] = valves.getNumOfOpen();
char buffer[256];
char topic[64];
sprintf(topic, "%s/info", mainTopic);
size_t n = serializeJson(doc, buffer);
client.publish(topic, buffer, n);
}