Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tank Level control & Drain valve closure
#1
Hi All,

Dan great program btw, I'm looking to add in level control to my rain water tank, once the level of the tank gets to low it will stop programs from running. The ultrasonic kit I'm using is weather proof probe kit https://core-electronics.com.au/weatherp...probe.html and have tested it with https://www.raspberrypi-spy.co.uk/2013/0...on-part-2/ (code script is on website) but since I'm a beginner just having some trouble adding it as a plugin. The second plugin I'd like to add is a gpio to go high to close drain actuators for x amount of time when the rain sensor has detected rain, and open once rain sensor has gone low. 
Reply
#2
Welcome,

Those sound like very useful plugins.
I will be glad to advise you on their development. First we will need to know a little more about your setup.

How is your Ras Pi connect to your irrigation system? In other words how many free GPIO pins do you have to work with?

SIP has existing code to handle input from a rain sensor. We should be able to use that to control your drain actuators. When the rain sensor changes there is a signal broadcast that can be used by plugins. An example is included in the signaling_examples.py file located in the plugins folder.

I'll need to think about how to handle input from the tank level sensor. Will the water level in the tank rise and fall during the growing season? That is, will the plugin need to check the tank level periodically or will it just need to stop all stations when the tank is too low?
Reply
#3
Thanks for the quick reply Dan,

The system will consist of a 3000litre tank that will be fed only from the rain off the roof to save costs on watering the garden. A pressure drop actuated pump running only off 240v, will have no inhibits from the Raspberry Pi Zero W. Off the Raspberry Pi is a 4 optocoupled relay, the first is setup as master to turn 240v supply needed by the water solenoids and drain actuators (24vdc and 24vac), worked out less expensive for parts and to save power being on the power supplies all the time. So there is only been 4 gpio used for the relays and two for the water level (gpio 11,12,13,15 and 16,18 respectivel).

I will have a look in the sinal_examples.py for the rain sensor signal. For the water level, this will need to be checked periodically for reference on lets say previous nights fall and before each program is started. It would be nice to see the water level on the front page down by the CPU temp.
Reply
#4
It sounds like you can use SIP's rain sensor feature to handle controlling your system without needing to make a plugin for that.

Go to SIP's OPTIOS page > Rain sensor and tick the box next to "Use Rain Sensor". Connect your rain sensor to pins 6 (ground) and 8.

It will stop all the relays when rain is detected.
Reply
#5
(2018 Oct 01, 01:17 AM)dan Wrote: It sounds like you can use SIP's rain sensor feature to handle controlling your system without needing to make a plugin for that.

Go to SIP's OPTIOS page > Rain sensor and tick the box next to "Use Rain Sensor". Connect your rain sensor to pins 6 (ground) and 8.

It will stop all the relays  when rain is detected.

For the Drain actuators? I will need to turn on one relay for the drain actuators. For the level? Will need a plugin for the code?
Reply
#6
I am not sure what you are asking.

If you need to have one relay work even if the rain sensor says there is rain you can.
Go to the STATIONS page and tick the box under "Ignore Rain" next to the station you want to stay active.

You will still need a plugin for the tank level.
Reply
#7
Hi Dan,

Sorry I'm new to this and willing to learn. I was asking when the rain sensor has detected rain, excluding the use of any station, to be able to run anytime, and to use a spare gpio to energize a relay to close the drain actuators. Sorry but I have very limited experience with python as well, but would it be easier to create a plugin from proto.py? 

With the water level, I was asking to have a constant readout of the water level on the home page down near the cpu temp. I'm not sure how to add this code (below) as a plugin to use and then have it as a selection to stop stations once water level is to low.
Code:
#!/usr/bin/python
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#|R|a|s|p|b|e|r|r|y|P|i|-|S|p|y|.|c|o|.|u|k|
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# ultrasonic_2.py
# Measure distance using an ultrasonic module
# in a loop.
#
# Author : Matt Hawkins
# Date   : 28/01/2013

# -----------------------
# Import required Python libraries
# -----------------------
import time
import RPi.GPIO as GPIO

# -----------------------
# Define some functions
# -----------------------

def measure():
 # This function measures a distance
 GPIO.output(GPIO_TRIGGER, True)
 time.sleep(0.00001)
 GPIO.output(GPIO_TRIGGER, False)
 start = time.time()

 while GPIO.input(GPIO_ECHO)==0:
   start = time.time()

 while GPIO.input(GPIO_ECHO)==1:
   stop = time.time()

 elapsed = stop-start
 distance = (elapsed * 34300)/2

 return distance

def measure_average():
 # This function takes 3 measurements and
 # returns the average.
 distance1=measure()
 time.sleep(0.1)
 distance2=measure()
 time.sleep(0.1)
 distance3=measure()
 distance = distance1 + distance2 + distance3
 distance = distance / 3
 return distance

# -----------------------
# Main Script
# -----------------------

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_TRIGGER = 23
GPIO_ECHO    = 24

print "Ultrasonic Measurement"

# Set pins as output and input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo

# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)

# Wrap main content in a try block so we can
# catch the user pressing CTRL-C and run the
# GPIO cleanup function. This will also prevent
# the user seeing lots of unnecessary error
# messages.
try:

 while True:

   distance = measure_average()
   print "Distance : %.1f" % distance
   time.sleep(1)

except KeyboardInterrupt:
 # User pressed CTRL-C
 # Reset GPIO settings
 GPIO.cleanup()
 
Best regards,

Ben
Reply
#8
Hi Dan,

Made an attempt for the water level plugin, see what you think for the first attempt. Still need help with adding the water level measurement read out as a percentage on the home page.

level_ultrasonic.py
Code:
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# this plugin checks the water level and if master switch is on stops all stations

import json  # for working with data file
import time
import sys
import traceback

import web  # web.py framework
import gv  # Get access to SIP's settings
import RPi.GPIO as GPIO
from urls import urls  # Get access to SIP's URLs
from sip import template_render  #  Needed for working with web.py templates
from webpages import ProtectedPage  # Needed for security
from helpers import stop_stations

# Add new URLs to access classes in this plugin.
urls.extend([
   '/level_ultrasonic-sp', 'plugins.level_ultrasonic.settings',
   '/level_ultrasonic-save', 'plugins.level_ultrasonic.save_settings',
   '/level_ultrasonic-spj', 'plugins.level_ultrasonic.json'

   ])

# Add this plugin to the PLUGINS menu ['Menu Name', 'URL'], (Optional)
gv.plugin_menu.append([_('Level Ultrasonic Plugin'), '/level_ultrasonic-sp'])

def measure():
 # This function measures a distance
 GPIO.output(GPIO_TRIGGER, True)
 time.sleep(0.00001)
 GPIO.output(GPIO_TRIGGER, False)
 start = time.time()

 while GPIO.input(GPIO_ECHO)==0:
   start = time.time()

 while GPIO.input(GPIO_ECHO)==1:
   stop = time.time()

 elapsed = stop-start
 distance = (elapsed * 34300)/2

 return distance

def measure_average():
 # This function takes 6 measurements and
 # returns the average.
 distance1=measure()
 time.sleep(0.1)
 distance2=measure()
 time.sleep(0.1)
 distance3=measure()
 time.sleep(0.1)
 distance4=measure()
 time.sleep(0.1)
 distance5=measure()
 time.sleep(0.1)
 distance6=measure()
 distance = distance1 + distance2 + distance3 + distance4 + distance5 + distance6
 distance = distance / 6
 return distance

# -----------------------
# Main Script
# -----------------------

# Use BCM GPIO references
# instead of physical pin numbers
GPIO.setmode(GPIO.BCM)

# Define GPIO to use on Pi
GPIO_TRIGGER = 23
GPIO_ECHO    = 24

# Set pins as output and input
GPIO.setup(GPIO_TRIGGER,GPIO.OUT)  # Trigger
GPIO.setup(GPIO_ECHO,GPIO.IN)      # Echo

# Set trigger to False (Low)
GPIO.output(GPIO_TRIGGER, False)

# Wrap main content in a try block so we can
# catch the user pressing CTRL-C and run the
# GPIO cleanup function. This will also prevent
# the user seeing lots of unnecessary error
# messages.
try:

 while True:

   distance = measure_average()
   time.sleep(1)
   if (gv.sd['mas'] != 0) and not (gv.sd['mm']):                   # if is use master station and not manual control
                       if gv.srvals[gv.sd['mas']] != 0:                              # if master station is ON
                           if measure_average() > 1800:            # if water level is greater then 1800 stop stations
                               stop_stations()

except KeyboardInterrupt:
 # User pressed CTRL-C
 # Reset GPIO settings
 GPIO.cleanup()


class settings(ProtectedPage):
   """
   Load an html page for entering plugin settings.
   """

   def GET(self):
       try:
           with open('./data/level_ultrasonic.json', 'r') as f:  # Read settings from json file if it exists
               settings = json.load(f)
       except IOError:  # If file does not exist return empty value
           settings = {}  # Default settings. can be list, dictionary, etc.
       return template_render.level_ultrasonic(settings)  # open settings page

class save_settings(ProtectedPage):
   """
   Save user input to json file.
   Will create or update file when SUBMIT button is clicked
   CheckBoxes only appear in qdict if they are checked.
   """

   def GET(self):
       qdict = web.input()  # Dictionary of values returned as query string from settings page.
#        print qdict  # for testing
       with open('./data/level_ultrasonic.json', 'w') as f:  # Edit: change name of json file
            json.dump(qdict, f) # save to file
       raise web.seeother('/')  # Return user to home page.

#  Run when plugin is loaded
empty_function()

level_ultrasonic.html
Code:
$def with(settings)
<!-- Edit: Replace "proto_vals" with settings values for your plugin if used-->

$var title: $_('Level_Ultrasonic') <!--Edit: Title to show on browser tab-->
$var page: level_ultrasonic  <!--Edit: page name, used internally-->
<script>

   // Initialize behaviors
   jQuery(document).ready(function(){

       jQuery("#cSubmit").click(function() {
           jQuery("#pluginForm").submit();
       });
       jQuery("button#cCancel").click(function(){
           window.location= baseUrl + "/";
       });

       jQuery("button#docButton").click(function(){
           window.open(baseUrl + "/static/docs/plugins/level_ultrsonic-docs.html", "_blank"); //Edit: replace "proto-docs.html"
       });

   });
</script>

<div id="plugin">
   <div class="title">Level Ultrasonic Plugin  <!--Edit: User page heading, Make relevant to your plugin-->
   <button class="execute" id="docButton" type="button" >$_('Help')</button>
   </div>

   <p>$_('Example Check Boxes')</p>
   <form id="pluginForm" action="${app_path('/level_ultrasonic-save')}" method="get"> <!--Edit: Replace "proto-save" with URL of plugin's class for saving settings-->

       <table class="optionList">

           <!--Check boxes-->
           <thead>
               <th class="stationNumber">$_('Heading')</th>  <!--Edit: Optional-->
               <th class="stationNumber">$_('Heading')</th>  <!--Edit: Optional-->
           </thead>
           <tr>
               <td style='text-transform: none;'>$_('Check Box 1'):</td>  <!--Edit-->
               <td><input type="checkbox" name="check-1"  ${"checked" if 'check-1' in settings else ""}></td>
           </tr>
           <tr>
               <td style='text-transform: none;'>$_('Check Box 2'):</td>  <!--Edit-->
               <td><input type="checkbox" name="check-2" ${"checked" if 'check-2' in settings else ""}></td>
           </tr>

       </table></br>

       <p>$_('Text Entry Fields')</p>  <!--Edit-->
       <table class="optionList">

           <!--Text fields-->
           <thead>
               <th class="stationNumber">$_('Heading')</th>  <!--Edit: Optional-->
               <th class="stationNumber">$_('Heading')</th>  <!--Edit: Optional-->
           </thead>

           <tr>
               <td style='text-transform: none;'>$_('Text Field 1'):</td>  <!--Edit-->
               <td><input type="text" name="text-1" value="${settings['text-1'] if 'text-1' in settings else '' }"></td>
           </tr>
           <tr>
               <td style='text-transform: none;'>$_('Text Field 2'):</td>  <!--Edit-->
               <td><input type="text" name="text-2" value="${settings['text-2'] if 'text-2' in settings else ''}"></td>
           </tr>

       </table>

   </form>

<div id="controls">
   <button id="cSubmit" class="submit"><b>$_('Submit')</b></button>
   <button id="cCancel" class="cancel danger">$_('Cancel')</button>
</div>
</div>

level_ultrasonic.manifest
Code:
A bare bones plugin designed to be used as a starting point for writing plugins.

##### List all plugin files below preceded by a blank line [file_name.ext path] relative to SIP directory #####

level_ultrasonic.py plugins
level_ultrasonic.html templates
level_ultrasonic.html static/docs/plugins
level_ultrasonic.json data (generated)
level_ultrasonic.manifest plugins/manifests

level_ultrasonic-docs.html
Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
    <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
    <TITLE>level_ultrasonic-docs.html</TITLE>
    <META NAME="GENERATOR" CONTENT="OpenOffice 4.1.1  (Win32)">
    <META NAME="CREATED" CONTENT="0;0">
    <META NAME="CHANGED" CONTENT="0;0">
    <META NAME="viewport" CONTENT="width=device-width, initial-scale=1.0">
   <link href="../../themes/basic/base.css" rel="stylesheet" type="text/css"/>
</HEAD>
<BODY LANG="en-US" BGCOLOR="#ffffff" DIR="LTR" STYLE="border: none; padding: 0in">
<H1><A NAME="Level-Ultrasonic-plugin-documentation"></A>Level Ultrasonic Plugin
Documentation</H1>
<H2 CLASS="western"><A NAME="about-the-level-ultrasonic-plugin"></A>About the
Level Ultrasonic Plugin</H2>
<P>The level ultrasonic plugin is designed as a starting point for creating new
plugins for SIP. It does not perform any useful action but contains
the basic components necessary for a functioning plugin.</P>
<P>The plugin includes the folowing files:</P>
<UL>
    <LI><P STYLE="margin-bottom: 0in"><STRONG>level_ultrasonic.py</STRONG><BR>The
    python program that does the actual work of the plugin. Location:
    <STRONG>SIP/plugins</STRONG></P>
    <LI><P STYLE="margin-bottom: 0in"><STRONG>level_ultrasonic.html</STRONG><BR>A
    web.py template that provides a user interface for the plugin. It
    includes both Python code and web page markup. Location:
    <STRONG>SIP/templates</STRONG></P>
    <LI><P STYLE="margin-bottom: 0in"><STRONG>level_ultrasonic-docs.html</STRONG><BR>This
    file. Provides documentation for the plugin including any special hardware needed and set up instructions. Location:
    <STRONG>SIP/static/docs/plugins</STRONG></P>
    <LI><P STYLE="margin-bottom: 0in"><STRONG>level_ultrasonic.manifest</STRONG><BR>A
    simple text file containing a list of each of the plugin&rsquo;s
    files with the path to it&rsquo;s location. The manifest is used by
    the plugin manager to install and uninstall the plugin. The file
    can also contain information about the plugin such as author, brief description, requirements, etc.
    Location: <STRONG>SIP/plugins/manifest</STRONG></P>
    <LI><P><STRONG>level_ultrasonic.json</STRONG><BR>An optional file used for
    persistant storage of plugin settings. It is created by the plugin
    the first time it is run and is not installed with the other files.
    This allows for software updates without overwriting existing
    settings. Location: <STRONG>SIP/data</STRONG></P>
</UL>
<H2 CLASS="western"><A NAME="using-the-level-ultrasonic-plugin"></A>Using the
Level Ultrasonic plugin</H2>
<P>This plugin is disabled by default. If you are reading this, the
proto plugin is probably enabled on your system. Otherwise you can
enable it using the plugin manager or by setting the group
permissions of the <STRONG>level_ultrasonic.py</STRONG> file to <STRONG>executable</STRONG>.
Once it is enabled, and the SIP program has been restarted, You can
verify it is working by selecting it from the PLUGINS drop down menu
of the main program&rsquo;s web interface. You should be taken to the
plugin&rsquo;s Settings page.</P>
<P>To begin creating a new plugin from proto you will need to
copy/rename each of the proto files you will be using in your
project. For example, on the command line, you can make a copy of the
proto.py file with a new name:</P>
<PRE CLASS="western" STYLE="margin-bottom: 0.2in"><CODE CLASS="western">sudo cp SIP/plugins/proto.py SIP/plugins/your-new-name.py</CODE></PRE><P>
Follow a similar procedure for the other files you will include in
your project.</P>
<P>The next step is to open your new Python file and edit the items
in the following list. See comments in the file for more information.</P>
<P>Edit these items:</P>
<UL>
    <LI><P STYLE="margin-bottom: 0in">URLs for plugin pages</P>
    <LI><P STYLE="margin-bottom: 0in">Name of plugin to be shown on
    plugins menu</P>
    <LI><P>Name of .json file for storing settings (optional)</P>
</UL>
<P>After you make the changes and save the file, check that the group
permission of the file is exicutable.</P>
<PRE CLASS="western" STYLE="margin-bottom: 0.2in"><CODE CLASS="western">sudo ls -l SIP/plugins/your-new-name.py</CODE></PRE><P>
The first column of the line for your plugin should look something
like <CODE CLASS="western">-rw-r-xr-- 1</CODE>. The x preceding the
third r is what counts.</P>
<P>If you need to change the setting you can use the plugin manager
or the command:</P>
<PRE CLASS="western" STYLE="margin-bottom: 0.2in"><CODE CLASS="western">sudo chmod g+x SIP/plugins/your-new-name.py</CODE></PRE><P>
to enable the plugin or:</P>
<PRE CLASS="western" STYLE="margin-bottom: 0.2in"><CODE CLASS="western">sudo chmod g-x SIP/plugins/your-new-name.py</CODE></PRE><P>
to disable it without affecting any other permissions.</P>
<P>Restart the SIP program and you should be able to access your new
plugin from the menu. If you entered a new name for the <STRONG>proto.json</STRONG>
file it should appear in the <STRONG>SIP/data</STRONG> directory
after you access your plugin for the first time.</P>
<P>If there is an error when you try to access your plugin, start the
SIP program manually.<BR>In the <STRONG>SIP directory</STRONG>
issue the following command:</P>
<PRE CLASS="western" STYLE="margin-bottom: 0.2in"><CODE CLASS="western">sudo python sip.py</CODE></PRE><P>
You will now be able to see messages from the program that can help
you figure out what went wrong.</P>
<P>For the most up-to-date and detailed information about writing
plugins see the <A HREF="https://github.com/Dan-in-CA/SIP_plugins/wiki">plugins
wiki</A>.</P>
</P>
</BODY>
</HTML>

Best regards,
Ben
Reply
#9
Hi Ben,

Wow you've done a lot. I will take a look and do some testing.
I now have a waterproof ultrasonic module so I can test the code with the actual sensor.

Putting the tank level on the home page will be a bit tricky and I need to look into the best way to do it.

You mentioned showing the tank level as a percentage. That was going to be one of my questions but you already answered it.

Another question I have is abut connecting the ultrasonic module directly to the RasPi. It means that the Pi will need to be located on or very close to the tank. Would you consider connecting the sensor to the Pi at a distance?

I have been working on a way to connect remote sensors such as soil moisture sensors, water flow sensors and pressure sensors using an Arduino which can  communicate with the Pi. The ultrasonic sensor could be used that way also.

I will try out your code and get back to you. It may be a couple of days.

Dan
Reply
#10
Hi Dan,

Cheers, but you've done all the hard yards, I'm just learning off the best!

I did modify the code for measurement to take 6 and then take the average as the weatherproof ultrasonic I have throws a significantly higher or lower value and doing this does smooth it over so to speak. For my situation the Raspberry Pi Zero W will be right beside the tank, so I wont be using an arduino but that's a great idea for remote sensors, could even include temperature probes, I'll be interested in seeing that!

Take your time, you've been a great help so far.

Best Regards,

Ben
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)