From 08f14424af96a150afb8e00e9c2ffd51c2b06081 Mon Sep 17 00:00:00 2001 From: Alexander Klein Date: Thu, 13 Apr 2023 18:09:26 +0200 Subject: [PATCH] switched to mqtt, added class valve --- .vscode/settings.json | 8 +++ include/config.h | 7 +- lib/Pump/pump.cpp | 10 +-- lib/Pump/pump.h | 2 +- lib/Valve/valve.cpp | 79 ++++++++++++++++++++ lib/Valve/valve.h | 40 +++++++++++ platformio.ini | 5 +- src/main.cpp | 162 +++++++++++++++++------------------------- 8 files changed, 205 insertions(+), 108 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..753944e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "cSpell.words": [ + "RCLK", + "SRCLK", + "SROE", + "SRSER" + ] +} \ No newline at end of file diff --git a/include/config.h b/include/config.h index 8a386c8..5a8e5c9 100644 --- a/include/config.h +++ b/include/config.h @@ -3,7 +3,7 @@ #define PRESSURE_PIN A7 #define BUTTON_PIN A6 #define SROE_PIN A3 -#define STATUS_LED_1_PIN A0 +#define STATUS_LED_1_PIN A0 // Error pump #define DISPLAY_ACTIVE_PIN 9 #define STATUS_LED_2_PIN 8 #define SRSER_PIN 7 @@ -11,4 +11,7 @@ #define RCLK_PIN 5 #define SSR_PIN 4 #define INT_ETH_PIN 3 -#define INT_HALL_PIN 2 \ No newline at end of file +#define INT_HALL_PIN 2 + +#define VALVE_COUNT 12 +const uint8_t valvePins[VALVE_COUNT] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; \ No newline at end of file diff --git a/lib/Pump/pump.cpp b/lib/Pump/pump.cpp index be904b1..0387553 100644 --- a/lib/Pump/pump.cpp +++ b/lib/Pump/pump.cpp @@ -51,7 +51,7 @@ void Pump::loop() { } } -void Pump::activate(uint32_t duration = 0) { +void Pump::activate(uint32_t duration) { this->startTime = millis(); if (duration) { this->state = State::Timer; @@ -72,15 +72,15 @@ void Pump::clearError() { } uint16_t Pump::getPressure() { - + return 0; } -uint16_t Pump::getRunningTime() { - +uint32_t Pump::getRunningTime() { + return millis() -this->startTime; } uint16_t Pump::getFlow() { - + return 0; } void Pump::checkSensors() { diff --git a/lib/Pump/pump.h b/lib/Pump/pump.h index 99dc259..68708bb 100644 --- a/lib/Pump/pump.h +++ b/lib/Pump/pump.h @@ -22,7 +22,7 @@ class Pump { void clearError(); uint16_t getPressure(); - uint16_t getRunningTime(); + uint32_t getRunningTime(); uint16_t getFlow(); State getState() { return this->state; } diff --git a/lib/Valve/valve.cpp b/lib/Valve/valve.cpp index e69de29..2a66cbe 100644 --- a/lib/Valve/valve.cpp +++ b/lib/Valve/valve.cpp @@ -0,0 +1,79 @@ +#include "valve.h" + +Valve::Valve() { + +} + +void Valve::loop() { + if (millis() - this->loopLastMillis < this->loopDelay) + return; + this->loopLastMillis = millis(); + + for (uint8_t i = 0; i < this->valveCount; i++) { + uint8_t minutesOn = (millis() - this->valves[i].startTime) / 1000; + if (minutesOn >= this->valves[i].duration) + this->close(i); + } +} + +void Valve::addShiftRegister(ShiftRegister *shiftRegister) { + this->shiftRegister = shiftRegister; +} + +void Valve::add(uint8_t pinNum, bool shiftRegister) { + if (this->valveCount == MAX_VALVES) + return; + + ValveData newValve; + newValve.pin = pinNum; + newValve.shiftRegister = shiftRegister; + this->valves[this->valveCount] = newValve; + this->valveCount++; +} + +void Valve::open(uint8_t valveNumber, uint8_t minutes) { + if (valveNumber >= this->valveCount) + return; + + this->valves[valveNumber].duration = minutes; + this->valves[valveNumber].startTime = millis(); + this->setValve(valveNumber, true); +} + +void Valve::close(uint8_t valveNumber) { + if (valveNumber >= this->valveCount) + return; + + this->valves[valveNumber].duration = 0; + this->setValve(valveNumber, false); +} + +void Valve::closeAll() { + for (uint8_t i = 0; i < this->valveCount; i++) { + this->valves[i].duration = 0; + this->setValve(i, false); + } +} + +uint8_t Valve::getNumOfOpen() { + uint8_t res = 0; + for (uint8_t i = 0; i < this->valveCount; i++) + if (this->valves[i].duration) + res++; + return res; +} + +uint8_t Valve::getTimeLeft(uint8_t valveNumber) { + if (valveNumber >= this->valveCount) + return -1; + + uint32_t millisOn = millis() - this->valves[valveNumber].startTime; + return this->valves[valveNumber].duration - (millisOn / 1000); +} + +void Valve::setValve(uint8_t valveNumber, bool state) { + if (this->valves[valveNumber].shiftRegister && this->shiftRegister) + this->shiftRegister->writePin(this->valves[valveNumber].pin, state); + else + digitalWrite(this->valves[valveNumber].pin, state); +} diff --git a/lib/Valve/valve.h b/lib/Valve/valve.h index e69de29..d143b50 100644 --- a/lib/Valve/valve.h +++ b/lib/Valve/valve.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#define MAX_VALVES 16 + +class Valve { + public: + struct ValveData { + uint8_t pin; + bool shiftRegister; + uint8_t duration; + uint32_t startTime; + }; + + Valve(); + + void loop(); + + void addShiftRegister(ShiftRegister *shiftRegister); + void add(uint8_t pinNum, bool shiftRegister); + + void open(uint8_t valveNumber, uint8_t minutes); + void close(uint8_t valveNumber); + void closeAll(); + + uint8_t getNumOfOpen(); + uint8_t getTimeLeft(uint8_t valveNumber); + + + private: + void setValve(uint8_t valveNumber, bool state); + + ShiftRegister* shiftRegister = nullptr; + + ValveData valves[MAX_VALVES]; + uint8_t valveCount = 0; + uint16_t loopDelay = 1000; + uint32_t loopLastMillis = 0; +}; \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 61ca2a5..b981ea1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -14,5 +14,6 @@ board = nanoatmega328new framework = arduino monitor_speed = 115200 lib_deps = - arduino-libraries/Ethernet@^2.0.1 - https://git.kleiax.de/PlatformIO-Libs/Shiftregister.git#v1.0 + arduino-libraries/Ethernet@^2.0.1 + https://git.kleiax.de/PlatformIO-Libs/Shiftregister.git#v1.0 + knolleary/PubSubClient@^2.8 diff --git a/src/main.cpp b/src/main.cpp index 158259e..118c689 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,121 +1,87 @@ #include #include #include +#include #include +#include + +#include "config.h" +#include "pump.h" +#include "valve.h" #define COUNT_HTTP_METHOD 3 #define METHOD_LENGTH 6 +#define BUFFER_SIZE 128 byte mac[] = { 0xC3, 0xF9, 0x7C, 0xB1, 0x8C, 0xF3 }; -IPAddress ip(192, 168, 13, 0); -IPAddress gateway(192, 168, 0, 1); -IPAddress subnet(255, 255, 128, 0); +// IPAddress ip(192, 168, 13, 0); +// IPAddress gateway(192, 168, 0, 1); +// IPAddress subnet(255, 255, 128, 0); -EthernetServer server(80); +IPAddress ip(192, 168, 178, 202); +IPAddress gateway(192, 168, 178, 1); +IPAddress subnet(255, 255, 255, 0); +IPAddress dns(192, 168, 178, 1); +IPAddress server(192, 168, 178, 35); +// IPAddress server(91, 121, 93, 94); -const byte const httpMethos[COUNT_HTTP_METHOD][METHOD_LENGTH] = { 'GET ', 'PATCH ', 'DELETE' }; +ShiftRegister reg(RCLK_PIN, SRCLK_PIN, SRSER_PIN, 2); +Pump pump(SSR_PIN, PRESSURE_PIN, INT_HALL_PIN, STATUS_LED_1_PIN); +Valve valves; +EthernetClient ethClient; +PubSubClient client(ethClient); -// ShiftRegister reg() - -void listenForEthernetClients(void); +void reconnect(); +void callback(char* topic, byte* payload, unsigned int length); void setup() { Serial.begin(115200); - Serial.println("Arduino Bewaesserung"); + Serial.println("Arduino Irrigation"); - Ethernet.begin(mac, ip); - server.begin(); + valves.addShiftRegister(®); + for (uint8_t i = 0; i < VALVE_COUNT; i++) + valves.add(valvePins[i], true); + valves.closeAll(); + + client.setServer(server, 1883); + client.setCallback(callback); + + Ethernet.begin(mac, ip, dns, gateway, subnet); + + // Allow the hardware to sort itself out + delay(1500); } void loop() { - listenForEthernetClients(); + if (!client.connected()) + reconnect(); + client.loop(); + pump.loop(); } -void listenForEthernetClients() { - EthernetClient client = server.available(); - if (!client) return; - - Serial.println("Got a client"); - byte buffer[256]; - - uint8_t method = -1; - - uint8_t i = 0; - uint8_t countChars = client.readBytesUntil(' ', buffer, METHOD_LENGTH); - for (countChars--; countChars < METHOD_LENGTH; countChars++ ) - buffer[countChars] = ' '; - for (uint8_t i = 0; i < COUNT_HTTP_METHOD; i++) - if (memcmp(buffer, httpMethos[i], METHOD_LENGTH)) { - method = i; - break; - } - - - - uint16_t len = client.available(); - if (len > 0) - client.read(buffer, len); - Serial.write(buffer, len); - - client.println("HTTP/1.1 200 OK"); - client.println("Content-Type: text/html"); - client.println(); - // print the current readings, in HTML format: - client.print("Temperature: "); - client.print("temperature"); - client.print(" degrees C"); - client.println("
"); - client.print("Pressure: lUl"); - client.print(" Pa"); - client.println("
"); - - client.stop(); - - - - - - - - - - // // an http request ends with a blank line - // boolean currentLineIsBlank = true; - // while (client.connected()) { - // if (client.available()) { - // char c = client.read(); - // Serial.print(c); - // // if you've gotten to the end of the line (received a newline - // // character) and the line is blank, the http request has ended, - // // so you can send a reply - // if (c == '\n' && currentLineIsBlank) { - // // send a standard http response header - // client.println("HTTP/1.1 200 OK"); - // client.println("Content-Type: text/html"); - // client.println(); - // // print the current readings, in HTML format: - // client.print("Temperature: "); - // client.print("temperature"); - // client.print(" degrees C"); - // client.println("
"); - // client.print("Pressure: lUl"); - // client.print(" Pa"); - // client.println("
"); - // break; - // } - // if (c == '\n') { - // // you're starting a new line - // currentLineIsBlank = true; - // } - // else if (c != '\r') { - // // you've gotten a character on the current line - // currentLineIsBlank = false; - // } - // } - // } - // give the web browser time to receive the data +void callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived ["); + Serial.print(topic); + Serial.print("] "); + for (unsigned int i=0;i