Měření aktuálního objemu vody v nádrži
V tomto článku si ukážeme, jak lze řešit měření výšky hladiny vody v nádrži (např. zásobník dešťové vody). Hodnoty si budeme přepočítávat na objem v litrech. V OpenHAB 3 zobrazíme aktuální hodnotu a procentualní hodnotu. K dispozici bude i graf historie hodnot.
Hardware
Ultrazvukový voděodolný senzor vzdálenosti JSN-SR04T
Pi-Home - pokud nemáte, viz sekci Jak na to
Software
OpenHAB
Aplikace
Tento senzor se skládá ze dvou částí, elektronické desky a voděodolného senzoru. Elektronickou část je tedy nutné uložit také do voděodolného pouzdra. Senzor pracuje na základě akustických vln. Více o funkci naleznete například zde: https://www.electronicwings.com/sensors-modules/ultrasonic-module-hc-sr04. Senzor dokáže měřit od cca 20 cm do 450 cm v úhlu cca 45 °. Je proto nutné, aby v blízkosti senzoru a také po stranách nebyly překážky, kde by mohlo dojít k rušení. Ideální je mít vlastní senzor v plastové trubce a umístit jej cca 25 cm nad maximem vodní hladiny doprostřed nádrže.
Postup
Senzor osadíme do libovolné trubky. Hlava senzoru má průměr 25 mm, případně lze zvolit trubku s větším vnitřním průměrem a vypolstrovat, aby v ní senzor držel. Trubku pak uchytíte v nádrži. Kabel od senzoru pak vede do elektronické desky. Elektronicka deska je pak přes UTP kabel připojena do domu do Arduina (cca 20m). Naše krabička je osazena těsnicí průchodkou pro UTP kabel. Zapojte čtyři libovolné žíly dle toho, jak to vypadá v zapojení na desce Arduina dle sketche (viz níže). Do Arduina nahrajeme sketch, který bude odečítávat hodnoty vzdálenosti. Dále je zde přepočet na objem nádrže a frekvence odečtu hodnoty. Zaměřte se a editujte tuto část sketche dle vaší nádrže. Kód je samozřejmě možné kombinovat a na jednom Arduinu sbírat hodnoty vzdálenosti, teplot, pir a dalších užitečných senzorů.
Celý sketch:
/*
Script to read volume of liquid medium in water tank
- connect to MQTT server
- publishes "Hello world - Arduino XYZ" to the topic
- read sensor value, calculate volume and filter results
- multiple arduino's with same generic sketch can run parallel to each other
- multiple arduino's need each to have a unique ip-addres, unique mac address and unique MQTT client-ID
- tested on arduino-mega with W5100 ethernet shield
*/
//MQTT
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
//Tank level
#include <NewPing.h>
#include <MedianFilter.h>
#include <Wire.h>//Tank Level
#define TRIGGER_PIN 3
#define ECHO_PIN 4
#define MAX_DISTANCE 200 // (in centimeters). Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
MedianFilter filter(31,0);//Time variable
unsigned long time_now = 0;//Char strings for MQTT
char tankDV[10];
//---------------------------------------------------------------------------// Arduino MAC address must be unique for every node in same network
byte mac[] = { 0xCC, 0xFA, 0x00, 0x1B, 0x19, 0x77 };// Unique static IP address of Arduino
IPAddress ip(192,168,4,101);// IP Address of your MQTT broker (OpenHAB server)
byte server[] = { 192,168,4,30 };// Handle and convert incoming MQTT messages ----------------------------------------
void callback(char* topic, byte * payload, unsigned int length) {
}// Initiate instances -----------------------------------
EthernetClient arduino_XYZ;
PubSubClient client(server, 1883, callback, arduino_XYZ);
//-------------------------------------------------------
void setup()
{
// Setup ethernet connection to MQTT broker
Ethernet.begin(mac, ip);
if (client.connect("arduino_XYZ", "openhabian", "openhabian")) { // change as desired - clientname must be unique for MQTT broker
client.publish("sensors","Hello world - here Arduino XYZ with IP 192.168.4.101");
}
}
//-----------------------------------------------
long lastReconnectAttempt = 0;boolean reconnect() {
if (client.connect("arduino_XYZ", "openhabian", "openhabian")) {
// Once connected, publish an announcement...
client.publish("sensors","Arduino XYZ - reconnected");
// ... and resubscribe
client.subscribe("sensors");
}
return client.connected();
}
//----------------------------------------------void loop()
{
if (!client.connected()) {
long now = millis();
if (now - lastReconnectAttempt > 5000) {
lastReconnectAttempt = now;
// Attempt to reconnect
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
} else {
// Client connectedclient.loop();
}
// Collect sensor data every 30 seconds. Change value 30000 ms to another if you want
if(millis() >= time_now + 30000){
time_now += 30000;//============TANK LEVEL SENSOR============================
unsigned int otank1,uStank1 = sonar.ping(); // Send ping, get ping time in microseconds (uStank1).
filter.in(uStank1);
otank1 = filter.out();
//Calculate volume in litres (add values in centimeters): ((sensor height from bottom - sensor value) * pi * r2)/1000
float cmtank1 = ((160-(otank1 / US_ROUNDTRIP_CM))*3.14*6400)/1000;
//Filter value - we should get only values between maximum volume of tank and minimum volume
if ((cmtank1 <=2700) && (cmtank1 >= 50)){
dtostrf(cmtank1,3, 0, tankDV);
client.publish("pihome/sensor/water/rain", tankDV);
}
}
delay(1000);
}// End of sketch ---------------------------------
OpenHAB
Do OpenHAB 3 dostaneme hodnoty ze senzoru následovně. Vytvoříme si Thing typu MQTT. Pak přidáme Channel. Moje záložka Code by v tomto případě vypadala takto:
UID: mqtt:topic:pihome:sensors-other
label: Sensors other
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:pihome
channels:
- id: SW101
channelTypeUID: mqtt:number
label: WaterTank Litres Rain
description: null
configuration:
stateTopic: pihome/sensor/water/rain
Pak vytvořte Item ze záložky Channels. Když už máte hodnotu v OpenHAB, pojďte si ji dát na plochu uživatelskeho rozhraní podle následujících screenů:
PS: Pokud hledáte co znamená hodnota SW101p - je to procentualní obsah vody v nádrži. Jak toto dostat? jednoduše si vytvořte prázdný item typu number "SW101p" a přidejte následující pravidlo. Pravidlo podělí aktuální objem jedním procentem. Pro mou nádrž je výpočet jednoho procenta následovný 2700 litrů / 100 = 27. Viz níže:
configuration: {}
triggers:
- id: "1"
configuration:
itemName: SW101
state: ""
previousState: ""
type: core.ItemStateChangeTrigger
conditions: []
actions:
- inputs: {}
id: "2"
configuration:
type: application/vnd.openhab.dsl.rule
script: "
\ sendCommand(SW101p, (SW101.state as Number)/27)
\ "
type: script.ScriptAction
Co dál?
Můžete přidat různe pravidla pro chování dalších zařízení a čerpadel, např:
- je-li stav nižší než 300 L, doplnit vodu z řádu
- je-li vyšší než 2500, přečerpat do další nádrže
- je-li nižší než 1000, nepoužívat k zálevce atd. atd.
Použité knihovny ke stažení: