вівторок, 25 вересня 2018 р.

MyHomeIoT: Рівень води Water Level шина I2C

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 можна використовувати з будь яким мікроконтролером для своїх поробок автоматики і систем розумного будинку написавши програмну підтримку до свого мікроконтролеру який будете використовувати.

Схема пристрою

Схема рівня води (тицяйте в зображення для збільшення)
Схема складається з мікросхеми PCF8574P, яка є двонаправленим розширювачем портів вводу/виводу з керуванням по I2C шині і має адресу 0x21. Та мікросхеми ULN2803A, яка є масивом транзисторів Дарлінгтона і має 8 транзисторів з загальним емітером та внутрішніми діодами для індуктивних навантажень (реле).
Перші чотири входи 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;
}

2 коментарі:

  1. Здрастуй, як би датчики рівня води були в цьому випадку? Я уявляю металеві бари? Я правильно Дякую зараз

    ВідповістиВидалити
    Відповіді
    1. Доброго дня. Так, правильно. Конструкція схожа на це:
      https://waterlevelcontrols.com/wp-content/uploads/2016/10/Float-Switch-Diagram-How-Do-Float-Switches-Work.jpg

      Видалити