Mises à jour multiples à l'interface web : visu de photos, renommage des templates Jinja, nouvelle configuration, préparation graphe
This commit is contained in:
		@@ -17,13 +17,23 @@ mqtt_pass = WaKaW9XMGUZ3rRJD
 | 
			
		||||
mqtt_qos = 2
 | 
			
		||||
mqtt_topic = huzzah0/#
 | 
			
		||||
 | 
			
		||||
[FLASK]
 | 
			
		||||
http_host = 0.0.0.0
 | 
			
		||||
http_listen_port = 5000
 | 
			
		||||
flask_debug = 1
 | 
			
		||||
flask_secret = 'blablabla'
 | 
			
		||||
 | 
			
		||||
flask_images_url = /urlsizer
 | 
			
		||||
flask_images_path = static/photos
 | 
			
		||||
flask_images_cache = cache/flask-images
 | 
			
		||||
 | 
			
		||||
[CAMERA]
 | 
			
		||||
camera_mqtt_topic = raspi0/camera
 | 
			
		||||
camera_resolution_x=2592
 | 
			
		||||
camera_resolution_y=1944
 | 
			
		||||
camera_warmup_time=2
 | 
			
		||||
camera_iso=0
 | 
			
		||||
camera_rotation=180
 | 
			
		||||
camera_rotation=0
 | 
			
		||||
camera_auto_white_balance=auto
 | 
			
		||||
camera_exposure_mode=auto
 | 
			
		||||
camera_contrast=0
 | 
			
		||||
 
 | 
			
		||||
@@ -20,10 +20,17 @@ from flask_sqlalchemy import SQLAlchemy
 | 
			
		||||
#####################
 | 
			
		||||
 | 
			
		||||
app = Flask(__name__)
 | 
			
		||||
app.config['SERVER_NAME'] = hostname + ":" + http_listen_port
 | 
			
		||||
app.config['SECRET_KEY'] = flask_secret
 | 
			
		||||
app.config['DEBUG'] = flask_debug
 | 
			
		||||
app.config['SQLALCHEMY_DATABASE_URI'] = sql_uri
 | 
			
		||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
 | 
			
		||||
app.config['BOOTSTRAP_USE_MINIFIED'] = False
 | 
			
		||||
app.config['BOOTSTRAP_SERVE_LOCAL'] = True
 | 
			
		||||
app.config['IMAGES_URL'] = flask_images_url
 | 
			
		||||
app.config['IMAGES_PATH'] = flask_images_path
 | 
			
		||||
app.config['IMAGES_CACHE'] = flask_images_cache
 | 
			
		||||
 | 
			
		||||
#app.config['SQLALCHEMY_POOL_RECYCLE'] = 600
 | 
			
		||||
 | 
			
		||||
######################
 | 
			
		||||
 
 | 
			
		||||
@@ -13,12 +13,14 @@ Created on Fri Aug 18 21:35:59 2017
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timedelta, timezone
 | 
			
		||||
from configparser import SafeConfigParser
 | 
			
		||||
import os, sys
 | 
			
		||||
import os, sys, socket
 | 
			
		||||
 | 
			
		||||
#################
 | 
			
		||||
# CONFIGURATION #
 | 
			
		||||
#################
 | 
			
		||||
 | 
			
		||||
hostname = socket.gethostname() + ".local"
 | 
			
		||||
 | 
			
		||||
script_path = os.path.dirname(sys.argv[0])
 | 
			
		||||
script_dir = os.path.abspath(script_path)
 | 
			
		||||
 | 
			
		||||
@@ -50,6 +52,17 @@ mqtt_auth       = {'username' : mqtt_user, 'password' : mqtt_pass}
 | 
			
		||||
mqtt_qos        = parser['MQTT'].get('mqtt_qos', fallback=0)
 | 
			
		||||
mqtt_topic      = parser['MQTT'].get('mqtt_topic', fallback='sensors/#')
 | 
			
		||||
 | 
			
		||||
#HTTP FLASK
 | 
			
		||||
http_host           = parser['FLASK'].get('http_host', fallback='127.0.0.1')
 | 
			
		||||
http_listen_port    = parser['FLASK'].get('http_listen_port', fallback='5000')
 | 
			
		||||
 | 
			
		||||
flask_debug         = bool(int(parser['FLASK'].get('flask_debug', fallback=1)))
 | 
			
		||||
flask_secret        = parser['FLASK'].get('flask_secret', fallback='random')
 | 
			
		||||
 | 
			
		||||
flask_images_url    = parser['FLASK'].get('flask_images_url', fallback='/urlsizer')
 | 
			
		||||
flask_images_path   = parser['FLASK'].get('flask_images_path', fallback='static/photos')
 | 
			
		||||
flask_images_cache  = parser['FLASK'].get('flask_images_cache', fallback='cache/flask-images')
 | 
			
		||||
 | 
			
		||||
#Camera
 | 
			
		||||
camera_mqtt_topic   = parser['CAMERA'].get('camera_mqtt_topic', fallback='raspi0/camera')
 | 
			
		||||
camera_resolution_x = int(parser['CAMERA'].get('camera_resolution_x', fallback='800'))
 | 
			
		||||
@@ -62,7 +75,7 @@ camera_expo_mode    = parser['CAMERA'].get('camera_exposure_mode', fallback='aut
 | 
			
		||||
camera_rotation     = int(parser['CAMERA'].get('camera_rotation', fallback=0))
 | 
			
		||||
camera_contrast     = int(parser['CAMERA'].get('camera_contrast', fallback=0))
 | 
			
		||||
 | 
			
		||||
photo_dir        = parser['CAMERA'].get('photo_dir', fallback='/home/pi/photos/')
 | 
			
		||||
photo_dir        = parser['CAMERA'].get('photo_dir', fallback='/home/pi/Cameteo/photos/')
 | 
			
		||||
photo_name       = parser['CAMERA'].get('photo_name', fallback='%%Y%%m%%d_%%H%%M%%S')
 | 
			
		||||
photo_format     = parser['CAMERA'].get('photo_format', fallback='jpg')
 | 
			
		||||
photo_extensions = {'jpeg': 'jpg',
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,11 @@ from flask_bootstrap import Bootstrap
 | 
			
		||||
from flask_nav import Nav
 | 
			
		||||
from flask_nav.elements import *
 | 
			
		||||
 | 
			
		||||
from bokeh.plotting import figure
 | 
			
		||||
from bokeh.embed import components
 | 
			
		||||
from bokeh.models import ColumnDataSource
 | 
			
		||||
from bokeh.resources import INLINE
 | 
			
		||||
 | 
			
		||||
########
 | 
			
		||||
# MAIN #
 | 
			
		||||
########
 | 
			
		||||
@@ -28,39 +33,81 @@ navbar = Navbar('Camétéo',
 | 
			
		||||
                View('Accueil', 'index'),
 | 
			
		||||
                View('Toutes les données', 'all_data'),
 | 
			
		||||
                Subgroup('Par données',
 | 
			
		||||
                        View("Température de l'air",  'by_data_type', dt='TA'),
 | 
			
		||||
                        View("Humidité relative",     'by_data_type', dt='HR'),
 | 
			
		||||
                        View("Pression atmosphérique",'by_data_type', dt='PA'),
 | 
			
		||||
                        View("Température de l'air",            'by_data_type', dt='AT'),
 | 
			
		||||
                        View("Humidité relative",               'by_data_type', dt='RH'),
 | 
			
		||||
                        View("Pression atmosphérique (locale)", 'by_data_type', dt='AP'),
 | 
			
		||||
                        View("Pression atmosphérique (mer)",    'by_data_type', dt='MSLP'),
 | 
			
		||||
                        View("Altitude",                        'by_data_type', dt='ALTI'),
 | 
			
		||||
                        ),
 | 
			
		||||
                Subgroup('Par capteur',                
 | 
			
		||||
                        View("Capteur BME280", 'by_sensor', sens = 'AdaBME280_1')
 | 
			
		||||
                        ),
 | 
			
		||||
                Subgroup('Photos',
 | 
			
		||||
                         View('Dernière Photo', 'picture', num=0),
 | 
			
		||||
                         View('Première Photo', 'picture', num=999999999),
 | 
			
		||||
                        ),
 | 
			
		||||
                View('Configuration', 'config_page')
 | 
			
		||||
                )
 | 
			
		||||
                
 | 
			
		||||
nav.register_element('top', navbar)
 | 
			
		||||
 | 
			
		||||
js_resources = INLINE.render_js()
 | 
			
		||||
css_resources = INLINE.render_css()
 | 
			
		||||
 | 
			
		||||
@app.route('/')
 | 
			
		||||
def index():
 | 
			
		||||
    return render_template('index.html')
 | 
			
		||||
    return render_template('index.tpl')
 | 
			
		||||
 | 
			
		||||
@app.route('/picture=<num>')
 | 
			
		||||
def picture(num):
 | 
			
		||||
    num=int(num)
 | 
			
		||||
    if num < 0 :
 | 
			
		||||
        num = 0
 | 
			
		||||
    pictures = Photo.query.order_by(Photo.file_date.desc())
 | 
			
		||||
    if num > pictures.count()-1:
 | 
			
		||||
        num = pictures.count()-1
 | 
			
		||||
    pict = pictures[num]
 | 
			
		||||
    return render_template('photos.tpl', picture_path = os.path.join("static/photos", pict.file_name), numero = num )
 | 
			
		||||
 | 
			
		||||
@app.route('/all_data')
 | 
			
		||||
def all_data():
 | 
			
		||||
    date_deb = datetime.utcnow()-timedelta(seconds=3600)
 | 
			
		||||
    res = Data.query.filter(Data.dbdate >= date_deb)
 | 
			
		||||
    return render_template('data_viz.html', dat=res.order_by(Data.dbdate.desc()).paginate(per_page=15))
 | 
			
		||||
    return render_template('data_viz.tpl', dat=res.order_by(Data.dbdate.desc()).paginate(per_page=15))
 | 
			
		||||
     
 | 
			
		||||
@app.route('/type_id=<dt>')
 | 
			
		||||
def by_data_type(dt):
 | 
			
		||||
    date_deb = datetime.utcnow()-timedelta(seconds=3600)
 | 
			
		||||
    res = Data.query.filter(Data.type_id == dt).filter(Data.dbdate >= date_deb)
 | 
			
		||||
    return render_template('data_viz.html', dat=res.order_by(Data.dbdate.desc()).paginate(per_page=15))
 | 
			
		||||
    #Récupération des données à afficher
 | 
			
		||||
    res = Data.query.filter(Data.type_id == dt).filter(Data.dbdate >= date_deb).order_by(Data.valdate)
 | 
			
		||||
    
 | 
			
		||||
    plot_data = ColumnDataSource(data=dict(x = res.values('valdate'), y = res.values('value')))
 | 
			
		||||
    
 | 
			
		||||
    #Préparation du graphique    
 | 
			
		||||
    data_plot = figure(tools        = TOOLS,
 | 
			
		||||
                       title        = dt,
 | 
			
		||||
                       x_axis_label = 'Date',
 | 
			
		||||
                       x_axis_type  = 'datetime',
 | 
			
		||||
                       y_axis_label = dt,
 | 
			
		||||
                       plot_height  = 400,
 | 
			
		||||
                       plot_width   = 800,
 | 
			
		||||
                       )
 | 
			
		||||
    data_plot.line('x', 'y', source=plot_data, line_width=2)
 | 
			
		||||
    
 | 
			
		||||
    script, div = components(data_plot)
 | 
			
		||||
    
 | 
			
		||||
    return render_template('data_graph.tpl', dat=res.order_by(Data.dbdate.desc()).paginate(per_page=15),
 | 
			
		||||
                           plot_script=script, 
 | 
			
		||||
                           plot_div=div,
 | 
			
		||||
                           js_resources=js_resources,
 | 
			
		||||
                           css_resources=css_resources,
 | 
			
		||||
                           )
 | 
			
		||||
    
 | 
			
		||||
@app.route('/sensor_id=<sens>')
 | 
			
		||||
def by_sensor(sens):
 | 
			
		||||
    date_deb = datetime.utcnow()-timedelta(seconds=3600)
 | 
			
		||||
    res = Data.query.filter(Data.sensor_id == sens).filter(Data.dbdate >= date_deb)
 | 
			
		||||
    return render_template('data_viz.html', dat=res.order_by(Data.dbdate.desc()).paginate(per_page=15))
 | 
			
		||||
    return render_template('data_viz.tpl', dat=res.order_by(Data.dbdate.desc()).paginate(per_page=15))
 | 
			
		||||
    
 | 
			
		||||
@app.route('/configuration', methods=['GET', 'POST'])
 | 
			
		||||
def config_page():
 | 
			
		||||
@@ -70,7 +117,7 @@ def config_page():
 | 
			
		||||
    else:
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    return render_template('config_page.html')
 | 
			
		||||
    return render_template('config_page.tpl')
 | 
			
		||||
    
 | 
			
		||||
if __name__=="__main__":
 | 
			
		||||
    app.run(host="0.0.0.0", debug=True)
 | 
			
		||||
    app.run(host="0.0.0.0")
 | 
			
		||||
							
								
								
									
										1
									
								
								cameteo-interface/static/photos
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								cameteo-interface/static/photos
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
../../photos
 | 
			
		||||
		Reference in New Issue
	
	Block a user