{"id":473762,"date":"2025-09-02T21:02:46","date_gmt":"2025-09-02T21:02:46","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=473762"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=473762","title":{"rendered":"<span>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430\u043c\u0438 \u043f\u043e\u043b\u0438\u0432\u0430 \u043d\u0430 Arduino Uno \u0441 \u0441\u0435\u043d\u0441\u043e\u0440\u0430\u043c\u0438 Capacitive Soil Moisture Sensor v2<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0425\u043e\u0447\u0443 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430\u043c\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043d\u0430\u00a0<strong>C++<\/strong>\u00a0\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u00a0<strong>Arduino<\/strong>.<\/p>\n<p>\u041d\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0442\u0438\u043f\u0430 Thread \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a(delay).<\/p>\n<p>\u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 \u0432 \u043a\u043b\u0430\u0441\u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430. \u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043d\u0430\u0434\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<pre><code class=\"cpp\">pumpController.addPump(SoilSensor(A0, 800, 100000), 2, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 1<\/code><\/pre>\n<p>\u0433\u0434\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0438\u043d \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u0440\u043e\u0433 \u0441\u0443\u0445\u043e\u0441\u0442\u0438, \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u0430\u0442\u0447\u0438\u043a\u0430, \u043f\u0438\u043d \u043d\u0430\u0441\u043e\u0441\u0430, \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430. \u043d\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c.<\/p>\n<p><strong>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c<\/strong>: <\/p>\n<p>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438\u00a0<code>SoilSensor, <\/code>PumpController, ProcessStats\u00a0\u0438\u00a0<code>Pump,<\/code>  \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u044b, \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u043c\u0438\u043a\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445 Arduino \u0438\u043b\u0438 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445.<\/p>\n<ul>\n<li>\n<p><strong>Arduino-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u00a0<code>pinMode()<\/code>,\u00a0<code>digitalWrite()<\/code>,\u00a0<code>analogRead()<\/code><\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b\u00a0<code>HIGH<\/code>,\u00a0<code>LOW<\/code><\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00a0<code>millis()<\/code>,\u00a0<code>micros()<\/code><\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442\u00a0<code>Serial<\/code>\u00a0\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Arduino\u00a0<code>setup()<\/code>\u00a0\u0438\u00a0<code>loop()<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code class=\"cpp\">\/\/ \u0418\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f HIGH \u0438 LOW const int MYHIGH = LOW; const int MYLOW = HIGH;  \/\/ \u0411\u0443\u0444\u0435\u0440 \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 char buffer[100];  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f struct ProcessStats {   unsigned long callCount = 0;   unsigned long totalTime = 0;   unsigned long minTime = 0xFFFFFFFF; \/\/ \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 unsigned long   unsigned long maxTime = 0;      void update(unsigned long executionTime) {     callCount++;     totalTime += executionTime;     if (executionTime &lt; minTime) minTime = executionTime;     if (executionTime &gt; maxTime) maxTime = executionTime;   }      unsigned long getAverageTime() const {     return callCount &gt; 0 ? totalTime \/ callCount : 0;   }      String getStatsString() const {     return \"(\" + String(callCount) +             \") \" + String(minTime) +             \"\/\" + String(maxTime) +             \"\/\" + String(getAverageTime());   } };  \/\/ \u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 ProcessStats globalProcessStats;  \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 class SoilSensor { private:   int soilPin;              \/\/ \u041f\u0438\u043d \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438   int dryThreshold;         \/\/ \u041f\u043e\u0440\u043e\u0433 \u0441\u0443\u0445\u043e\u0441\u0442\u0438   unsigned long checkInterval; \/\/ \u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438   unsigned long lastCheckTime; \/\/ \u0412\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438  public:   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440   SoilSensor(int soilPin, int dryThreshold, unsigned long checkInterval)     : soilPin(soilPin), dryThreshold(dryThreshold), checkInterval(checkInterval), lastCheckTime(0) {}    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u043f\u0440\u0438\u0448\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438   bool isCheckTime() {     return millis() - lastCheckTime &gt;= checkInterval;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438   int readMoisture() {     \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438     lastCheckTime = millis();     return analogRead(soilPin);   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u0438\u0432\u0430   bool needsWatering(int moisture) {     return moisture &gt;= dryThreshold;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0435   String getInfo(int moisture, int getPumpPin) {     return String(millis() \/1000) + \" \u0441\u0435\u043a. - \u0414\u0430\u0442\u0447\u0438\u043a \" + String(soilPin) +             \"(p=\"+ String(getPumpPin)+\"): \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u044c=\" + String(moisture) +             \"(\" + String(dryThreshold) +            \")\" + String(moisture - dryThreshold) +            \" | \" + globalProcessStats.getStatsString();   }    \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b   int getSoilPin() const { return soilPin; }   int getDryThreshold() const { return dryThreshold; }   unsigned long getCheckInterval() const { return checkInterval; }   unsigned long getLastCheckTime() const { return lastCheckTime; } };  \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u043e\u043c class Pump { private:   SoilSensor sensor;        \/\/ \u041e\u0431\u044a\u0435\u043a\u0442 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 (\u043a\u043e\u043f\u0438\u044f)   int pumpPin;              \/\/ \u041f\u0438\u043d \u0440\u0435\u043b\u0435 \u043d\u0430\u0441\u043e\u0441\u0430   unsigned long pumpDuration; \/\/ \u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430   bool isPumping;           \/\/ \u0424\u043b\u0430\u0433 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0441\u043e\u0441\u0430   unsigned long pumpStartTime; \/\/ \u0412\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430  public:   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 SoilSensor   Pump(SoilSensor sensor, int pumpPin, unsigned long pumpDuration)     : sensor(sensor), pumpPin(pumpPin), pumpDuration(pumpDuration),        isPumping(false), pumpStartTime(0) {}    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0438\u043d\u0430 \u043d\u0430\u0441\u043e\u0441\u0430   void setupPin() {     pinMode(pumpPin, OUTPUT);   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0438\u0441\u0442\u0435\u043a\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430   bool isPumpTimeExpired() {     return millis() - pumpStartTime &gt;= pumpDuration;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430   void startPumping() {     digitalWrite(pumpPin, MYHIGH);     isPumping = true;     pumpStartTime = millis();     Serial.println(\"\u041d\u0430\u0441\u043e\u0441 \u043d\u0430 \u043f\u0438\u043d\u0435 \" + String(pumpPin) + \" \u0432\u043a\u043b\u044e\u0447\u0435\u043d s=\" + String(getSensor().getSoilPin()) + \"\");   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430   void stopPumping() {     digitalWrite(pumpPin, MYLOW);     isPumping = false;     Serial.println(\"\u041d\u0430\u0441\u043e\u0441 \u043d\u0430 \u043f\u0438\u043d\u0435 \" + String(pumpPin) + \" \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\");   }    \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u0441\u043e\u0441\u0430   void process() {     unsigned long startTime = micros(); \/\/ \u0417\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430          \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u043b\u0438 \u043d\u0430\u0441\u043e\u0441 \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442     if (isPumping) {       \/\/ \u0415\u0441\u043b\u0438 \u043d\u0430\u0441\u043e\u0441 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0435 \u0438\u0441\u0442\u0435\u043a\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b       if (isPumpTimeExpired()) {         stopPumping();       }              unsigned long endTime = micros(); \/\/ \u0417\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f       globalProcessStats.update(endTime - startTime); \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443       return; \/\/ \u041f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u043d\u0430\u0441\u043e\u0441 \u0430\u043a\u0442\u0438\u0432\u0435\u043d     }          \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043f\u0440\u0438\u0448\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u0430\u0442\u0447\u0438\u043a\u0430     if (sensor.isCheckTime()) {       int moisture = sensor.readMoisture();              \/\/ \u0412\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u043c\u043e\u043d\u0438\u0442\u043e\u0440 \u043f\u043e\u0440\u0442\u0430       Serial.println(sensor.getInfo(moisture, getPumpPin()));        \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043b\u0438 \u0441\u0443\u0445\u0430\u044f \u043f\u043e\u0447\u0432\u0430       if (sensor.needsWatering(moisture)) {         startPumping();       }     }          unsigned long endTime = micros(); \/\/ \u0417\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f     globalProcessStats.update(endTime - startTime); \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443   }    \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b   bool getIsPumping() const { return isPumping; }   unsigned long getPumpStartTime() const { return pumpStartTime; }   unsigned long getPumpDuration() const { return pumpDuration; }   SoilSensor getSensor() const { return sensor; }   int getPumpPin() const { return pumpPin; } };  \/\/ \u041a\u043b\u0430\u0441\u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 class PumpController { private:   Pump** pumps;           \/\/ \u041c\u0430\u0441\u0441\u0438\u0432 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 \u043d\u0430\u0441\u043e\u0441\u044b   int pumpCount;          \/\/ \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432   int maxPumps;           \/\/ \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432  public:   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440   PumpController(int maxPumps = 10) : pumpCount(0), maxPumps(maxPumps) {     pumps = new Pump*[maxPumps];     for (int i = 0; i &lt; maxPumps; i++) {       pumps[i] = nullptr;     }   }    \/\/ \u0414\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u043f\u0430\u043c\u044f\u0442\u0438   ~PumpController() {     for (int i = 0; i &lt; pumpCount; i++) {       delete pumps[i];     }     delete[] pumps;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430   bool addPump(SoilSensor sensor, int pumpPin, unsigned long pumpDuration) {     if (pumpCount &gt;= maxPumps) {       Serial.println(\"\u041e\u0448\u0438\u0431\u043a\u0430: \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432\");       return false;     }          pumps[pumpCount] = new Pump(sensor, pumpPin, pumpDuration);     pumpCount++;     return true;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0430 setup   void setup() {     for (int i = 0; i &lt; pumpCount; i++) {       pumps[i]-&gt;setupPin();       pumps[i]-&gt;stopPumping();     }     Serial.println(\"\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u043b\u0438\u0432\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430\");     Serial.println(\"\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432: \" + String(pumpCount));   }    \/\/ \u041c\u0435\u0442\u043e\u0434 process \u0434\u043b\u044f loop   void process() {     for (int i = 0; i &lt; pumpCount; i++) {       pumps[i]-&gt;process();     }   }    \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b   int getPumpCount() const { return pumpCount; }   int getMaxPumps() const { return maxPumps; } };  \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 PumpController pumpController(10); \/\/ \u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 10 \u043d\u0430\u0441\u043e\u0441\u043e\u0432  void setup() {   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430   Serial.begin(9600);      \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   pumpController.addPump(SoilSensor(A0, 800, 100000), 2, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 1   pumpController.addPump(SoilSensor(A1, 275, 16000), 3, 2000);   \/\/ \u041d\u0430\u0441\u043e\u0441 2   pumpController.addPump(SoilSensor(A2, 600, 700000), 4, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 3   pumpController.addPump(SoilSensor(A3, 700, 7000000), 5, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 4      \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430   pumpController.setup(); }  void loop() {   \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0441\u0435\u0445 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   pumpController.process(); }<\/code><\/pre>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/113\/9cf\/c15\/1139cfc156ca867c2ace4677a7573479.jpg\" alt=\"\u042d\u0442\u043e \u043d\u0430\u0441\u043e\u0441 \u0441 \u043f\u043e\u043f\u043b\u0430\u0432\u043a\u043e\u043c\" title=\"\u042d\u0442\u043e \u043d\u0430\u0441\u043e\u0441 \u0441 \u043f\u043e\u043f\u043b\u0430\u0432\u043a\u043e\u043c\" width=\"960\" height=\"1280\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/113\/9cf\/c15\/1139cfc156ca867c2ace4677a7573479.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/113\/9cf\/c15\/1139cfc156ca867c2ace4677a7573479.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u043e \u043d\u0430\u0441\u043e\u0441 \u0441 \u043f\u043e\u043f\u043b\u0430\u0432\u043a\u043e\u043c<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9b2\/753\/d5b\/9b2753d5ba5629c775a1b9d91eabd301.jpg\" alt=\"\u044d\u0442\u043e \u0441\u0435\u043d\u0441\u043e\u0440 Capacitive Soil Moisture Sensor v2\" title=\"\u044d\u0442\u043e \u0441\u0435\u043d\u0441\u043e\u0440 Capacitive Soil Moisture Sensor v2\" width=\"1280\" height=\"960\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/9b2\/753\/d5b\/9b2753d5ba5629c775a1b9d91eabd301.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9b2\/753\/d5b\/9b2753d5ba5629c775a1b9d91eabd301.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u044d\u0442\u043e \u0441\u0435\u043d\u0441\u043e\u0440 Capacitive Soil Moisture Sensor v2<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b1e\/c65\/b53\/b1ec65b53bd86a45708845ae29412339.jpg\" alt=\"\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430\" title=\"\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430\" width=\"1280\" height=\"960\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/b1e\/c65\/b53\/b1ec65b53bd86a45708845ae29412339.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b1e\/c65\/b53\/b1ec65b53bd86a45708845ae29412339.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u041e\u0436\u0438\u0434\u0430\u044e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/943302\/\"> https:\/\/habr.com\/ru\/articles\/943302\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0425\u043e\u0447\u0443 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430\u043c\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043d\u0430\u00a0<strong>C++<\/strong>\u00a0\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u00a0<strong>Arduino<\/strong>.<\/p>\n<p>\u041d\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0442\u0438\u043f\u0430 Thread \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430 \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a(delay).<\/p>\n<p>\u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 \u0432 \u043a\u043b\u0430\u0441\u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430. \u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043d\u0430\u0434\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<pre><code class=\"cpp\">pumpController.addPump(SoilSensor(A0, 800, 100000), 2, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 1<\/code><\/pre>\n<p>\u0433\u0434\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0438\u043d \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u0440\u043e\u0433 \u0441\u0443\u0445\u043e\u0441\u0442\u0438, \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u0430\u0442\u0447\u0438\u043a\u0430, \u043f\u0438\u043d \u043d\u0430\u0441\u043e\u0441\u0430, \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430. \u043d\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0438 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c.<\/p>\n<p><strong>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c<\/strong>: <\/p>\n<p>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438\u00a0<code>SoilSensor, <\/code>PumpController, ProcessStats\u00a0\u0438\u00a0<code>Pump,<\/code>  \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u044b, \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u043c\u0438\u043a\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445 Arduino \u0438\u043b\u0438 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445.<\/p>\n<ul>\n<li>\n<p><strong>Arduino-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438\u00a0<code>pinMode()<\/code>,\u00a0<code>digitalWrite()<\/code>,\u00a0<code>analogRead()<\/code><\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b\u00a0<code>HIGH<\/code>,\u00a0<code>LOW<\/code><\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00a0<code>millis()<\/code>,\u00a0<code>micros()<\/code><\/p>\n<\/li>\n<li>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442\u00a0<code>Serial<\/code>\u00a0\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u043e\u043c<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Arduino\u00a0<code>setup()<\/code>\u00a0\u0438\u00a0<code>loop()<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre><code class=\"cpp\">\/\/ \u0418\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f HIGH \u0438 LOW const int MYHIGH = LOW; const int MYLOW = HIGH;  \/\/ \u0411\u0443\u0444\u0435\u0440 \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 char buffer[100];  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f struct ProcessStats {   unsigned long callCount = 0;   unsigned long totalTime = 0;   unsigned long minTime = 0xFFFFFFFF; \/\/ \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 unsigned long   unsigned long maxTime = 0;      void update(unsigned long executionTime) {     callCount++;     totalTime += executionTime;     if (executionTime &lt; minTime) minTime = executionTime;     if (executionTime &gt; maxTime) maxTime = executionTime;   }      unsigned long getAverageTime() const {     return callCount &gt; 0 ? totalTime \/ callCount : 0;   }      String getStatsString() const {     return \"(\" + String(callCount) +             \") \" + String(minTime) +             \"\/\" + String(maxTime) +             \"\/\" + String(getAverageTime());   } };  \/\/ \u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 ProcessStats globalProcessStats;  \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438 class SoilSensor { private:   int soilPin;              \/\/ \u041f\u0438\u043d \u0434\u0430\u0442\u0447\u0438\u043a\u0430 \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438   int dryThreshold;         \/\/ \u041f\u043e\u0440\u043e\u0433 \u0441\u0443\u0445\u043e\u0441\u0442\u0438   unsigned long checkInterval; \/\/ \u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438   unsigned long lastCheckTime; \/\/ \u0412\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438  public:   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440   SoilSensor(int soilPin, int dryThreshold, unsigned long checkInterval)     : soilPin(soilPin), dryThreshold(dryThreshold), checkInterval(checkInterval), lastCheckTime(0) {}    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u043f\u0440\u0438\u0448\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438   bool isCheckTime() {     return millis() - lastCheckTime &gt;= checkInterval;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u0438   int readMoisture() {     \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438     lastCheckTime = millis();     return analogRead(soilPin);   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u0438\u0432\u0430   bool needsWatering(int moisture) {     return moisture &gt;= dryThreshold;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0435   String getInfo(int moisture, int getPumpPin) {     return String(millis() \/1000) + \" \u0441\u0435\u043a. - \u0414\u0430\u0442\u0447\u0438\u043a \" + String(soilPin) +             \"(p=\"+ String(getPumpPin)+\"): \u0432\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u044c=\" + String(moisture) +             \"(\" + String(dryThreshold) +            \")\" + String(moisture - dryThreshold) +            \" | \" + globalProcessStats.getStatsString();   }    \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b   int getSoilPin() const { return soilPin; }   int getDryThreshold() const { return dryThreshold; }   unsigned long getCheckInterval() const { return checkInterval; }   unsigned long getLastCheckTime() const { return lastCheckTime; } };  \/\/ \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u043e\u043c class Pump { private:   SoilSensor sensor;        \/\/ \u041e\u0431\u044a\u0435\u043a\u0442 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 (\u043a\u043e\u043f\u0438\u044f)   int pumpPin;              \/\/ \u041f\u0438\u043d \u0440\u0435\u043b\u0435 \u043d\u0430\u0441\u043e\u0441\u0430   unsigned long pumpDuration; \/\/ \u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430   bool isPumping;           \/\/ \u0424\u043b\u0430\u0433 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0441\u043e\u0441\u0430   unsigned long pumpStartTime; \/\/ \u0412\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430  public:   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 SoilSensor   Pump(SoilSensor sensor, int pumpPin, unsigned long pumpDuration)     : sensor(sensor), pumpPin(pumpPin), pumpDuration(pumpDuration),        isPumping(false), pumpStartTime(0) {}    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0438\u043d\u0430 \u043d\u0430\u0441\u043e\u0441\u0430   void setupPin() {     pinMode(pumpPin, OUTPUT);   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0438\u0441\u0442\u0435\u043a\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0441\u043e\u0441\u0430   bool isPumpTimeExpired() {     return millis() - pumpStartTime &gt;= pumpDuration;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430   void startPumping() {     digitalWrite(pumpPin, MYHIGH);     isPumping = true;     pumpStartTime = millis();     Serial.println(\"\u041d\u0430\u0441\u043e\u0441 \u043d\u0430 \u043f\u0438\u043d\u0435 \" + String(pumpPin) + \" \u0432\u043a\u043b\u044e\u0447\u0435\u043d s=\" + String(getSensor().getSoilPin()) + \"\");   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430   void stopPumping() {     digitalWrite(pumpPin, MYLOW);     isPumping = false;     Serial.println(\"\u041d\u0430\u0441\u043e\u0441 \u043d\u0430 \u043f\u0438\u043d\u0435 \" + String(pumpPin) + \" \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\");   }    \/\/ \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u0441\u043e\u0441\u0430   void process() {     unsigned long startTime = micros(); \/\/ \u0417\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0447\u0430\u043b\u0430          \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u043b\u0438 \u043d\u0430\u0441\u043e\u0441 \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442     if (isPumping) {       \/\/ \u0415\u0441\u043b\u0438 \u043d\u0430\u0441\u043e\u0441 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043d\u0435 \u0438\u0441\u0442\u0435\u043a\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b       if (isPumpTimeExpired()) {         stopPumping();       }              unsigned long endTime = micros(); \/\/ \u0417\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f       globalProcessStats.update(endTime - startTime); \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443       return; \/\/ \u041f\u0440\u0435\u0440\u044b\u0432\u0430\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u043d\u0430\u0441\u043e\u0441 \u0430\u043a\u0442\u0438\u0432\u0435\u043d     }          \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043f\u0440\u0438\u0448\u043b\u043e \u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u0430\u0442\u0447\u0438\u043a\u0430     if (sensor.isCheckTime()) {       int moisture = sensor.readMoisture();              \/\/ \u0412\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u043c\u043e\u043d\u0438\u0442\u043e\u0440 \u043f\u043e\u0440\u0442\u0430       Serial.println(sensor.getInfo(moisture, getPumpPin()));        \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043b\u0438 \u0441\u0443\u0445\u0430\u044f \u043f\u043e\u0447\u0432\u0430       if (sensor.needsWatering(moisture)) {         startPumping();       }     }          unsigned long endTime = micros(); \/\/ \u0417\u0430\u0441\u0435\u043a\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f     globalProcessStats.update(endTime - startTime); \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443   }    \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b   bool getIsPumping() const { return isPumping; }   unsigned long getPumpStartTime() const { return pumpStartTime; }   unsigned long getPumpDuration() const { return pumpDuration; }   SoilSensor getSensor() const { return sensor; }   int getPumpPin() const { return pumpPin; } };  \/\/ \u041a\u043b\u0430\u0441\u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 class PumpController { private:   Pump** pumps;           \/\/ \u041c\u0430\u0441\u0441\u0438\u0432 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 \u043d\u0430\u0441\u043e\u0441\u044b   int pumpCount;          \/\/ \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432   int maxPumps;           \/\/ \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432  public:   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440   PumpController(int maxPumps = 10) : pumpCount(0), maxPumps(maxPumps) {     pumps = new Pump*[maxPumps];     for (int i = 0; i &lt; maxPumps; i++) {       pumps[i] = nullptr;     }   }    \/\/ \u0414\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u043f\u0430\u043c\u044f\u0442\u0438   ~PumpController() {     for (int i = 0; i &lt; pumpCount; i++) {       delete pumps[i];     }     delete[] pumps;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u043e\u0441\u0430   bool addPump(SoilSensor sensor, int pumpPin, unsigned long pumpDuration) {     if (pumpCount &gt;= maxPumps) {       Serial.println(\"\u041e\u0448\u0438\u0431\u043a\u0430: \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432\");       return false;     }          pumps[pumpCount] = new Pump(sensor, pumpPin, pumpDuration);     pumpCount++;     return true;   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0430 setup   void setup() {     for (int i = 0; i &lt; pumpCount; i++) {       pumps[i]-&gt;setupPin();       pumps[i]-&gt;stopPumping();     }     Serial.println(\"\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u043b\u0438\u0432\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430\");     Serial.println(\"\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0441\u043e\u0441\u043e\u0432: \" + String(pumpCount));   }    \/\/ \u041c\u0435\u0442\u043e\u0434 process \u0434\u043b\u044f loop   void process() {     for (int i = 0; i &lt; pumpCount; i++) {       pumps[i]-&gt;process();     }   }    \/\/ \u0413\u0435\u0442\u0442\u0435\u0440\u044b   int getPumpCount() const { return pumpCount; }   int getMaxPumps() const { return maxPumps; } };  \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 PumpController pumpController(10); \/\/ \u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 10 \u043d\u0430\u0441\u043e\u0441\u043e\u0432  void setup() {   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430   Serial.begin(9600);      \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   pumpController.addPump(SoilSensor(A0, 800, 100000), 2, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 1   pumpController.addPump(SoilSensor(A1, 275, 16000), 3, 2000);   \/\/ \u041d\u0430\u0441\u043e\u0441 2   pumpController.addPump(SoilSensor(A2, 600, 700000), 4, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 3   pumpController.addPump(SoilSensor(A3, 700, 7000000), 5, 2000);  \/\/ \u041d\u0430\u0441\u043e\u0441 4      \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430   pumpController.setup(); }  void loop() {   \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0441\u0435\u0445 \u043d\u0430\u0441\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   pumpController.process(); }<\/code><\/pre>\n<figure class=\"full-width\">\n<div><figcaption>\u042d\u0442\u043e \u043d\u0430\u0441\u043e\u0441 \u0441 \u043f\u043e\u043f\u043b\u0430\u0432\u043a\u043e\u043c<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\">\n<div><figcaption>\u044d\u0442\u043e \u0441\u0435\u043d\u0441\u043e\u0440 Capacitive Soil Moisture Sensor v2<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\">\n<div><figcaption>\u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u041e\u0436\u0438\u0434\u0430\u044e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438 \u0438 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/943302\/\"> https:\/\/habr.com\/ru\/articles\/943302\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-473762","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/473762","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=473762"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/473762\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=473762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=473762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=473762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}