Add web page
This commit is contained in:
		
							
								
								
									
										27
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
{
 | 
			
		||||
    // Use IntelliSense to learn about possible attributes.
 | 
			
		||||
    // Hover to view descriptions of existing attributes.
 | 
			
		||||
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 | 
			
		||||
    "version": "0.2.0",
 | 
			
		||||
    "configurations": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Python: Flask",
 | 
			
		||||
            "type": "python",
 | 
			
		||||
            "request": "launch",
 | 
			
		||||
            "module": "flask",
 | 
			
		||||
            "env": {
 | 
			
		||||
                "FLASK_APP": "greenhouse/app.py",
 | 
			
		||||
                "FLASK_ENV": "development",
 | 
			
		||||
                "FLASK_DEBUG": "0"
 | 
			
		||||
            },
 | 
			
		||||
            "args": [
 | 
			
		||||
                "run",
 | 
			
		||||
                "--no-debugger",
 | 
			
		||||
                "--no-reload",
 | 
			
		||||
                "--host=0.0.0.0",
 | 
			
		||||
                "--port=8000"
 | 
			
		||||
            ],
 | 
			
		||||
            "jinja": true
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
from .app import app
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										119
									
								
								greenhouse/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								greenhouse/app.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
from flask import Flask
 | 
			
		||||
from flask import render_template
 | 
			
		||||
from flask import redirect
 | 
			
		||||
from flask import url_for
 | 
			
		||||
from flask import make_response
 | 
			
		||||
from flask import request
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timedelta
 | 
			
		||||
from threading import Thread
 | 
			
		||||
from time import sleep
 | 
			
		||||
 | 
			
		||||
from w1thermsensor import W1ThermSensor
 | 
			
		||||
import RPi.GPIO as GPIO
 | 
			
		||||
 | 
			
		||||
sensor = W1ThermSensor()
 | 
			
		||||
water_pin = 26  #17/27/22
 | 
			
		||||
heat_pin = 20
 | 
			
		||||
 | 
			
		||||
heat_state = False
 | 
			
		||||
 | 
			
		||||
GPIO.setwarnings(False)
 | 
			
		||||
GPIO.setmode(GPIO.BCM)
 | 
			
		||||
GPIO.setup(water_pin, GPIO.OUT)
 | 
			
		||||
 | 
			
		||||
class Heat(Thread):
 | 
			
		||||
    def __init__(self, pin):
 | 
			
		||||
        super(Heat, self).__init__()
 | 
			
		||||
        self.__pin = pin
 | 
			
		||||
        self.__state = False
 | 
			
		||||
        GPIO.setup(pin, GPIO.OUT)
 | 
			
		||||
        if GPIO.input(pin):
 | 
			
		||||
            self.__state = True
 | 
			
		||||
        self.__run_condition = True
 | 
			
		||||
        self.__next_update = datetime.now()
 | 
			
		||||
 | 
			
		||||
    def on(self):
 | 
			
		||||
        self.__state = True
 | 
			
		||||
        GPIO.output(self.__pin, 1)
 | 
			
		||||
 | 
			
		||||
    def off(self):
 | 
			
		||||
        self.__state = False
 | 
			
		||||
        GPIO.output(self.__pin, 0)
 | 
			
		||||
 | 
			
		||||
    def run(self):
 | 
			
		||||
        self.__next_update = datetime.now()
 | 
			
		||||
        while self.__run_condition:
 | 
			
		||||
            now = datetime.now()
 | 
			
		||||
            if now >= self.__next_update:
 | 
			
		||||
                if self.__state:
 | 
			
		||||
                    # Do a power cycle to prevent auto-poweroff
 | 
			
		||||
                    GPIO.output(self.__pin, 0)
 | 
			
		||||
                    sleep(5)
 | 
			
		||||
                    GPIO.output(self.__pin, 1)
 | 
			
		||||
                self.__next_update = now + timedelta(minutes=5)
 | 
			
		||||
            sleep(1)
 | 
			
		||||
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        self.__run_condition = False
 | 
			
		||||
        self.join()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def state(self):
 | 
			
		||||
        return self.__state
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
heat = Heat(heat_pin)
 | 
			
		||||
heat.start()
 | 
			
		||||
 | 
			
		||||
app = Flask(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/')
 | 
			
		||||
def index():
 | 
			
		||||
    return render_template('index.html')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/sample', methods=['GET'])
 | 
			
		||||
def get_sample():
 | 
			
		||||
    global heat
 | 
			
		||||
    global sensor
 | 
			
		||||
    try:
 | 
			
		||||
        temperature = f"{float(sensor.get_temperature()):.1f}"
 | 
			
		||||
    except SensorNotReadyError:
 | 
			
		||||
        temperature = None
 | 
			
		||||
 | 
			
		||||
    water_state = False
 | 
			
		||||
    if GPIO.input(water_pin):
 | 
			
		||||
        water_state = True
 | 
			
		||||
 | 
			
		||||
    res = {}
 | 
			
		||||
    res["id"] = str(1)
 | 
			
		||||
    if(temperature):
 | 
			
		||||
        res["temperature"] = temperature
 | 
			
		||||
    res["water"] = water_state
 | 
			
		||||
    res["heat"] = heat.state()
 | 
			
		||||
    return res
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/sample', methods=['PATCH'])
 | 
			
		||||
def patch_reroute():
 | 
			
		||||
    global heat
 | 
			
		||||
    record = json.loads(request.data)
 | 
			
		||||
    if "water" in record:
 | 
			
		||||
        water_state = record["water"]
 | 
			
		||||
        if water_state:
 | 
			
		||||
            GPIO.output(water_pin, 1)
 | 
			
		||||
        else:
 | 
			
		||||
            GPIO.output(water_pin, 0)
 | 
			
		||||
    if "heat" in record:
 | 
			
		||||
        heat_state = record["heat"]
 | 
			
		||||
        if heat_state:
 | 
			
		||||
            heat.on()
 | 
			
		||||
        else:
 | 
			
		||||
            heat.off()
 | 
			
		||||
 | 
			
		||||
    res = make_response("", 204)
 | 
			
		||||
    return res
 | 
			
		||||
							
								
								
									
										35
									
								
								greenhouse/static/css/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								greenhouse/static/css/style.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
html, body {
 | 
			
		||||
    font-size: 22px !important;
 | 
			
		||||
    font-family: arial, verdana, helvetica, sans-serif;
 | 
			
		||||
    color: #b6b6b6;
 | 
			
		||||
    background:  #282929;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 {text-align: center;}
 | 
			
		||||
p {text-align: center;}
 | 
			
		||||
div {text-align: center;}
 | 
			
		||||
 | 
			
		||||
.center {
 | 
			
		||||
    margin-left: auto;
 | 
			
		||||
    margin-right: auto;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type="submit" i] {
 | 
			
		||||
    color: #b6b6b6;
 | 
			
		||||
    background-color: #282929;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    margin: 10px 0;
 | 
			
		||||
    border-color: #b6b6b6;
 | 
			
		||||
    border-width: 3px;
 | 
			
		||||
    border-radius: 18px;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
td {
 | 
			
		||||
    padding: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.table_left {
 | 
			
		||||
    text-align: right;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								greenhouse/static/scripts/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								greenhouse/static/scripts/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
var on_switch_heat = function() {
 | 
			
		||||
    var state = true;
 | 
			
		||||
    if(document.getElementById("heat_switch").value == "ausschalten") {
 | 
			
		||||
        state = false;
 | 
			
		||||
    }
 | 
			
		||||
    var json_str = JSON.stringify({"id": "1", "heat": state});
 | 
			
		||||
    patch_sample(json_str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var on_switch_water = function() {
 | 
			
		||||
    var state = true;
 | 
			
		||||
    if(document.getElementById("water_switch").value == "ausschalten") {
 | 
			
		||||
        state = false;
 | 
			
		||||
    }
 | 
			
		||||
    var json_str = JSON.stringify({"id": "1", "water": state});
 | 
			
		||||
    patch_sample(json_str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var patch_http = new XMLHttpRequest();
 | 
			
		||||
var patch_sample = function(sample) {
 | 
			
		||||
    patch_http.abort();
 | 
			
		||||
    patch_http.open("PATCH", "/sample");
 | 
			
		||||
    patch_http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
 | 
			
		||||
    patch_http.send(sample);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var get_sample = function (event) {
 | 
			
		||||
    var sample = JSON.parse(event)
 | 
			
		||||
    output = "einschalten"
 | 
			
		||||
    out_state = "aus"
 | 
			
		||||
    if(sample.water) {
 | 
			
		||||
        output = "ausschalten"
 | 
			
		||||
        out_state = "an"
 | 
			
		||||
    }
 | 
			
		||||
    document.getElementById("temperature_value").innerHTML = sample.temperature + " °C";
 | 
			
		||||
    document.getElementById("water_switch").value = output;
 | 
			
		||||
    document.getElementById("water_state").innerHTML = out_state;
 | 
			
		||||
    if(sample.heat) {
 | 
			
		||||
        output = "ausschalten"
 | 
			
		||||
        out_state = "an"
 | 
			
		||||
    } else {
 | 
			
		||||
        output = "einschalten"
 | 
			
		||||
        out_state = "aus"
 | 
			
		||||
    }
 | 
			
		||||
    document.getElementById("heat_switch").value = output;
 | 
			
		||||
    document.getElementById("heat_state").innerHTML = out_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var http = new XMLHttpRequest();
 | 
			
		||||
http.onreadystatechange = function () {
 | 
			
		||||
    if (http.readyState === 4) {
 | 
			
		||||
    var status = http.status;
 | 
			
		||||
    if (status === 0 || (status >= 200 && status < 400)) {
 | 
			
		||||
        // The request has been completed successfully
 | 
			
		||||
        get_sample(http.responseText);
 | 
			
		||||
        setTimeout(function () {
 | 
			
		||||
            http.open("GET", 'sample');
 | 
			
		||||
            http.send();
 | 
			
		||||
        }, 500);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // request error
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
http.open("GET", "sample");
 | 
			
		||||
http.send();
 | 
			
		||||
							
								
								
									
										36
									
								
								greenhouse/templates/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								greenhouse/templates/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <title>Gewächshaus</title>
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
        <link href="/static/css/style.css" rel="stylesheet">
 | 
			
		||||
        <script src="/static/scripts/index.js"></script>
 | 
			
		||||
    </head>
 | 
			
		||||
 | 
			
		||||
    <body>
 | 
			
		||||
        <h1>Gewächshaus</h1>
 | 
			
		||||
 | 
			
		||||
        <table class="center">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>Temperatur </td>
 | 
			
		||||
                <td id="temperature_value"></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
        <table class="center">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td class="table_left">Heizung </td>
 | 
			
		||||
                <td id="heat_state"></td>
 | 
			
		||||
                <td class="input">
 | 
			
		||||
                    <input id="heat_switch" type="submit" value="" onclick="on_switch_heat()"></input>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td class="left">Bewässerung </td>
 | 
			
		||||
                <td class="center" id="water_state"></td>
 | 
			
		||||
                <td class="input">
 | 
			
		||||
                    <input id="water_switch" type="submit" value="" onclick="on_switch_water()"></input>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										27
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								setup.py
									
									
									
									
									
								
							@@ -1,29 +1,16 @@
 | 
			
		||||
#!/usr/bin/python3
 | 
			
		||||
'''
 | 
			
		||||
@author: Thomas Klaehn <tkl@blackfinn.de>
 | 
			
		||||
'''
 | 
			
		||||
from setuptools import setup
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import shutil
 | 
			
		||||
import stat
 | 
			
		||||
import sys
 | 
			
		||||
from setuptools import setup
 | 
			
		||||
 | 
			
		||||
NAME = 'greenhouse'
 | 
			
		||||
VERSION = '1.0.0'
 | 
			
		||||
NAME = 'Greenhouse'
 | 
			
		||||
VERSION = '1'
 | 
			
		||||
AUTHOR = 'Thomas Klaehn'
 | 
			
		||||
EMAIL = 'tkl@blackfinn.de'
 | 
			
		||||
SYSTEMD_SCRIPTS = ['greenhouse.service']
 | 
			
		||||
PACKAGES = ['greenhouse']
 | 
			
		||||
PACKAGE_DIRS = {'greenhouse':'greenhouse'}
 | 
			
		||||
REQUIRES = ['RPi.GPIO', 'w1thermsensor']
 | 
			
		||||
REQUIRES = ['Flask', 'w1thermsensor', 'RPi.GPIO']
 | 
			
		||||
 | 
			
		||||
SYSTEMD_PATH = '/lib/systemd/system/'
 | 
			
		||||
 | 
			
		||||
if sys.argv[1] == 'install':
 | 
			
		||||
    for script in SYSTEMD_SCRIPTS:
 | 
			
		||||
        shutil.copyfile(script, os.path.join(SYSTEMD_PATH, script))
 | 
			
		||||
        os.chmod(os.path.join(SYSTEMD_PATH, script), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
 | 
			
		||||
    setup(name=NAME, version=VERSION, author=AUTHOR, author_email=EMAIL, package_dir=PACKAGE_DIRS, packages=PACKAGES, install_requires=REQUIRES)
 | 
			
		||||
elif sys.argv[1] == 'sdist':
 | 
			
		||||
    setup(name=NAME, version=VERSION, author=AUTHOR, author_email=EMAIL, package_dir=PACKAGE_DIRS, packages=PACKAGES, install_requires=REQUIRES,
 | 
			
		||||
          scripts=SYSTEMD_SCRIPTS)
 | 
			
		||||
setup(name=NAME, version=VERSION, long_description=__doc__, author=AUTHOR, author_email=EMAIL,
 | 
			
		||||
      packages=PACKAGES, include_package_data=True, zip_safe=False, install_requires=REQUIRES)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user