MyHomeIoT Water Level
Рівень води MyHomeIoT Water Level призначений для контролю рівня води, та керуванням впускним і випускним клапаном по шині I2C з мікроконтролера. Приєднавши цю плату до Sonoff Basic (TH), або до будь якого пристрою на ESP8266, схемно сумісного з Sonoff basic (TH) та прошитого прошивкою MyHomeIoT починаючи з версії 1.1.4 і вище, до шини I2C, отримуєте контроль рівня води (чотири рівня: пустий, 1/4, 1/2, 3/4 і повний) плюс керування впускним і випускним клапаном зі світлодіодною індикацією і зворотнім зв'язком, як з додатку blynk app, так і з кнопки на самій платі. В додачу два тижневих планувальника для встановлення потрібного рівня води.Також цей Water Level можна використовувати з будь яким мікроконтролером для своїх поробок автоматики і систем розумного будинку написавши програмну підтримку до свого мікроконтролеру який будете використовувати.
Схема пристрою
Схема рівня води (тицяйте в зображення для збільшення) |
Перші чотири входи IN1 - IN4 мікросхеми ULN2803A використовуються для визначення рівня води. Виходи OUT5 і OUT6 мікросхеми ULN2803A керують впускним і випускним клапаном. А OUT7 керує світлодіодним індикатором режиму роботи. OUT8 не використовується (резерв), тому можна замість мікросхеми ULN2803A застосувати UNL2003.
Мікросхема PCF8574P - двонаправлений розширювач портів вводу/виводу з шиною I2C
Кнопка S1 - встановлення потрібного рівня води.
Світлодіод D2 - для індикації режимів роботи та помилок сенсору.
Реле К1, К2 - керування впускним і випускним клапаном
Транзистор Q1 - захист від переливу води у випадку, якщо мікроконтролер "завис" або не працює з якихось причин. Можна без транзистору, тоді OUT5 мікросхеми ULN2803A з'єднати на пряму з реле К1 (вивід 2 на схемі).
Демонстраційний код
/* Name: pcf8574_water_level.ino Created: 7/16/2018 8:59:19 AM Author: Andriy */ #include <Ticker.h> #include <Wire.h> #include <pcf8574_esp.h> #define ADDRESS_WATER_LEVEL 0x21 // Address PCF8574 on the I2C bus #define SDA 4 // Pin SDA wire #define SCL 5 // Pin SCL wire typedef enum { empty = 0x00, quarter = 0x40, half = 0x80, threeQuarters = 0xC0, full = 0xFE, errorSensor = 0xFF }WaterLevelEnum; typedef enum { sensor_0, sensor_1, sensor_2, sensor_3, intake_pump, outlet_pump, led_indicator, button }WaterLevelPortEnum; typedef struct { bool triggerInit = false; // трігер чи є такий пристрій в системі bool triggerButton = false; // трігер натискання і відпускання кнопки bool triggerStart = false; // трігер старту встановлення рівня води bool stateLed = false; // стан світлодіодного індікатора увімк/вимкн bool stateRelay[2] = { false, false }; // стан впускного і випускного реле uint8_t requiredWaterLevel = full; uint8_t currentWaterLevel = empty; }WaterLevelTypeDef; WaterLevelTypeDef waterLevelStruct; PCF857x waterLevelDevice(ADDRESS_WATER_LEVEL, &Wire, false); Ticker tickerWaterLevel; static void wl_Run(bool setOutletPump); static uint8_t wl_GetWaterLevel(void); static void wl_SetWaterLevel(uint8_t level); static void wl_ReadKey(void); static void wl_Control(bool setOutletPump); static void wl_ErrorLedStatus(void); static void wl_Action(bool state, bool stateIntakePump, bool stateOutletPump, String str); // the setup function runs once when you press reset or power the board void setup() { Serial.begin(115200); Wire.begin(SDA, SCL); // ініціалізуємо рівень води waterLevelDevice.begin(0x8F); // встановлюємо потрібний рівень wl_SetWaterLevel(half); // взнаємо поточний рівень води і заносимо до структури waterLevelStruct.currentWaterLevel = wl_GetWaterLevel(); if (waterLevelStruct.currentWaterLevel != errorSensor) { wl_Action(false, false, false, "Device water level is OK!"); if (tickerWaterLevel.active()) { tickerWaterLevel.detach(); waterLevelDevice.write(led_indicator, LOW); } } else { wl_Action(false, false, false, "Device water level is sensor error!"); if (!tickerWaterLevel.active()) { tickerWaterLevel.attach(0.2, wl_ErrorLedStatus); } } } // the loop function runs over and over again until power down or reset void loop() { wl_Run(true); } static void wl_Run(bool setOutletPump) { wl_ReadKey(); wl_Control(setOutletPump); } static void wl_ReadKey(void) { if (!waterLevelDevice.read(button) && !waterLevelStruct.triggerButton) { waterLevelStruct.triggerButton = true; waterLevelStruct.triggerStart = !waterLevelStruct.triggerStart; } else if (waterLevelDevice.read(button) && waterLevelStruct.triggerButton) { waterLevelStruct.triggerButton = false; } } static void wl_Control(bool setOutletPump) { if (waterLevelStruct.triggerStart) { waterLevelStruct.currentWaterLevel = wl_GetWaterLevel(); if (waterLevelStruct.currentWaterLevel == errorSensor) { wl_Action(false, false, false, "Error water sensor"); if (!tickerWaterLevel.active()) { tickerWaterLevel.attach(0.2, wl_ErrorLedStatus); } } else { if (tickerWaterLevel.active()) { tickerWaterLevel.detach(); waterLevelDevice.write(led_indicator, LOW); } if (waterLevelStruct.currentWaterLevel == waterLevelStruct.requiredWaterLevel) { wl_Action(false, false, false, "The tank has already reached the required level"); } else if (waterLevelStruct.currentWaterLevel < waterLevelStruct.requiredWaterLevel) { if (!waterLevelStruct.stateRelay[0]) { wl_Action(true, true, false, "Intake Pump ON"); } } else if (waterLevelStruct.currentWaterLevel > waterLevelStruct.requiredWaterLevel) { if (setOutletPump) { if (!waterLevelStruct.stateRelay[1]) { wl_Action(true, false, true, "Outlet Pump ON"); } } } } } else { if (waterLevelStruct.stateRelay[0]) { wl_Action(false, false, false, "Intake Pump OFF"); } if (waterLevelStruct.stateRelay[1]) { wl_Action(false, false, false, "Outlet Pump OFF"); } } } static void wl_Action(bool state, bool stateIntakePump, bool stateOutletPump, String str) { waterLevelStruct.triggerStart = state; waterLevelStruct.stateLed = state; waterLevelStruct.stateRelay[0] = stateIntakePump; waterLevelStruct.stateRelay[1] = stateOutletPump; Serial.println(str); Serial.print("Current water level is "); switch (waterLevelStruct.currentWaterLevel) { case empty: Serial.println("empty"); break; case quarter: Serial.println("1/4"); break; case half: Serial.println("1/2"); break; case threeQuarters: Serial.println("3/4"); break; case full: Serial.println("full"); break; case errorSensor: Serial.println("error"); break; default: break; } waterLevelDevice.write(led_indicator, waterLevelStruct.stateLed); waterLevelDevice.write(intake_pump, waterLevelStruct.stateRelay[0]); waterLevelDevice.write(outlet_pump, waterLevelStruct.stateRelay[1]); } static void wl_ErrorLedStatus(void) { waterLevelDevice.toggle(led_indicator); } static uint8_t wl_GetWaterLevel(void) { uint8_t level = (waterLevelDevice.read8() & 0xF) ^ 0x0F; if (level != 0b0000 && level != 0b0001 &&\ level != 0b0011 && level != 0b0111 && level != 0b1111) { return errorSensor; } else { if (level == 0b0000) return empty; else if (level == 0b0001) return quarter; else if (level == 0b0011) return half; else if (level == 0b0111) return threeQuarters; else if (level == 0b1111) return full; } } static void wl_SetWaterLevel(uint8_t level) { waterLevelStruct.requiredWaterLevel = level; }