From e897b59d1fe63b89f15a93fabb22199e5346f545 Mon Sep 17 00:00:00 2001 From: Pierrick C Date: Mon, 18 Sep 2017 22:37:04 +0200 Subject: [PATCH] Ajout du support de la camera du Raspberry Pi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Séparation de la partie configuration du module "commun" --- cameteo-interface/cameteo.conf | 18 +++++- cameteo-interface/cameteo.py | 41 +------------- cameteo-interface/cameteo_conf.py | 67 +++++++++++++++++++++++ cameteo-interface/mqtt2epaper.py | 34 +++++++----- cameteo-interface/picam+mqtt.py | 91 +++++++++++++++++++++---------- 5 files changed, 164 insertions(+), 87 deletions(-) create mode 100644 cameteo-interface/cameteo_conf.py diff --git a/cameteo-interface/cameteo.conf b/cameteo-interface/cameteo.conf index 7a80afd..041d27d 100644 --- a/cameteo-interface/cameteo.conf +++ b/cameteo-interface/cameteo.conf @@ -11,14 +11,26 @@ sql_verbose = 0 [MQTT] mqtt_host = aro-yuno mqtt_port = 1883 -mqtt_client_id = mqtt2sql +mqtt_client_id = cameteo mqtt_user = arofarn mqtt_pass = WaKaW9XMGUZ3rRJD -mqtt_qos = 1 +mqtt_qos = 2 mqtt_topic = huzzah0/# [CAMERA] camera_mqtt_topic = raspi0/camera +camera_resolution_x=2592 +camera_resolution_y=1944 +camera_warmup_time=2 +camera_iso=0 +camera_rotation=0 +camera_auto_white_balance=auto +camera_exposure_mode=auto +camera_contrast=0 + +photo_dir=/home/pi/Cameteo/photos/ +photo_name=test_%%Y%%m%%d_%%H%%M%%S +photo_format=jpeg [MISC] -TimeZone = 0 +TimeZone=2 diff --git a/cameteo-interface/cameteo.py b/cameteo-interface/cameteo.py index 372ade6..8481955 100644 --- a/cameteo-interface/cameteo.py +++ b/cameteo-interface/cameteo.py @@ -11,48 +11,9 @@ Created on Fri Aug 18 21:35:59 2017 # IMPORTS # ########### -from datetime import datetime, timedelta -from configparser import ConfigParser +from cameteo_conf import * from flask import Flask from flask_sqlalchemy import SQLAlchemy -import os, sys - -################# -# CONFIGURATION # -################# - -script_path = os.path.dirname(sys.argv[0]) -script_dir = os.path.abspath(script_path) - -parser = ConfigParser() -parser.read(script_dir + '/cameteo.conf') - -#Misc -TimeZone = parser['MISC'].get('TimeZone', fallback=0) - -#SQL -sql_host = parser['SQL'].get('sql_host', fallback='localhost') -sql_port = parser['SQL'].get('sql_port', fallback=3306) -sql_base = parser['SQL'].get('sql_base', fallback='cameteo') -sql_user = parser['SQL'].get('sql_user', fallback='cameteo') -sql_pass = parser['SQL'].get('sql_pass', fallback='oetemac') -sql_sys = parser['SQL'].get('sql_sys', fallback='mysql') -sql_api = parser['SQL'].get('sql_api', fallback='pymysql') -sql_verbose = bool(int(parser['SQL'].get('sql_verbose', fallback=0))) - -sql_uri = sql_sys + '+' + sql_api + '://' + sql_user + ':' + sql_pass + '@' + sql_host + ':' + sql_port + '/' + sql_base - -#MQTT -mqtt_host = parser['MQTT'].get('mqtt_host', fallback='localhost') -mqtt_port = int(parser['MQTT'].get('mqtt_port', fallback=1883)) -mqtt_client_id = parser['MQTT'].get('mqtt_client_id', fallback='mqtt2sql') -mqtt_user = parser['MQTT'].get('mqtt_user', fallback='cameteo') -mqtt_pass = parser['MQTT'].get('mqtt_pass', fallback='oetemac') -mqtt_qos = parser['MQTT'].get('mqtt_qos', fallback=0) -mqtt_topic = parser['MQTT'].get('mqtt_topic', fallback='sensors/#') - -#Camera -camera_mqtt_topic = parser['CAMERA'].get('camera_mqtt_topic', fallback='raspi0/camera') ##################### # Flask & SQLAchemy # diff --git a/cameteo-interface/cameteo_conf.py b/cameteo-interface/cameteo_conf.py new file mode 100644 index 0000000..2c310ae --- /dev/null +++ b/cameteo-interface/cameteo_conf.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +""" +Configuration du projet Camétéo + +Created on Fri Aug 18 21:35:59 2017 + +@author: arofarn +""" + +########### +# IMPORTS # +########### + +from datetime import datetime, timedelta, timezone +from configparser import SafeConfigParser +import os, sys + +################# +# CONFIGURATION # +################# + +script_path = os.path.dirname(sys.argv[0]) +script_dir = os.path.abspath(script_path) + +parser = SafeConfigParser(allow_no_value=True) +parser.read(script_dir + '/cameteo.conf') + +#Misc +TimeZone = timezone(timedelta(hours=int(parser['MISC'].get('TimeZone', fallback=0)))) + +#SQL +sql_host = parser['SQL'].get('sql_host', fallback='localhost') +sql_port = parser['SQL'].get('sql_port', fallback=3306) +sql_base = parser['SQL'].get('sql_base', fallback='cameteo') +sql_user = parser['SQL'].get('sql_user', fallback='cameteo') +sql_pass = parser['SQL'].get('sql_pass', fallback='oetemac') +sql_sys = parser['SQL'].get('sql_sys', fallback='mysql') +sql_api = parser['SQL'].get('sql_api', fallback='pymysql') +sql_verbose = bool(int(parser['SQL'].get('sql_verbose', fallback=0))) + +sql_uri = sql_sys + '+' + sql_api + '://' + sql_user + ':' + sql_pass + '@' + sql_host + ':' + sql_port + '/' + sql_base + +#MQTT +mqtt_host = parser['MQTT'].get('mqtt_host', fallback='localhost') +mqtt_port = int(parser['MQTT'].get('mqtt_port', fallback=1883)) +mqtt_client_id = parser['MQTT'].get('mqtt_client_id', fallback='mqtt2sql') +mqtt_user = parser['MQTT'].get('mqtt_user', fallback='cameteo') +mqtt_pass = parser['MQTT'].get('mqtt_pass', fallback='oetemac') +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/#') + +#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')) +camera_resolution_y = int(parser['CAMERA'].get('camera_resolution_y', fallback='600')) +camera_resolution = (camera_resolution_x, camera_resolution_y) +camera_warmup_time = int(parser['CAMERA'].get('camera_warmup_time', fallback=2)) +camera_iso = int(parser['CAMERA'].get('camera_iso', fallback=0)) +camera_awb = parser['CAMERA'].get('camera_auto_white_balance', fallback='auto') +camera_expo_mode = parser['CAMERA'].get('camera_exposure_mode', fallback='auto') +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_name = parser['CAMERA'].get('photo_name', fallback='%%Y%%m%%d_%%H%%M%%S') +photo_format = parser['CAMERA'].get('photo_format', fallback='jpg') diff --git a/cameteo-interface/mqtt2epaper.py b/cameteo-interface/mqtt2epaper.py index 16f3749..e3be8d2 100644 --- a/cameteo-interface/mqtt2epaper.py +++ b/cameteo-interface/mqtt2epaper.py @@ -1,19 +1,15 @@ -# Affichage de données arrivant sur un MQTT -# sur un écran ePaper -# Auteur : Arofarn -# v0.1 - -################# -# Configuration # -################# - +# -*- coding: utf-8 -*- +""" +Display data from MQTT broker on ePaper screen +@author: arofarn +""" ########### # IMPORTS # ########### -from cameteo import * +from cameteo_conf import * import paho.mqtt.client as mqtt from spidev import SpiDev import EPD_driver @@ -31,8 +27,9 @@ def on_connect(client, userdata, flags, rc): print(mqtt.connack_string(rc)) if rc == 0: print("Subscribing to %s ..." % mqtt_topic) - client.subscribe(mqtt_topic) - client.subscribe(camera_mqtt_topic + "/#") + client.subscribe([(mqtt_topic, 0), + (camera_mqtt_topic + "/#", 0)] + ) print("OK") #Callback de gestion des messages arrivant au MQTT : @@ -70,13 +67,20 @@ def on_message_date(client, userdata, msg): print("Date : " + payload) try: d = datetime.strptime(payload, "%H:%M:%S %d/%m/%Y") - disp.Dis_String(0, 17, d.strftime("%d/%m/%Y %H:%M:%S"), 16) + disp.Dis_String(0, 17, datetime.strftime(d + TimeZone.utcoffset(None), "%d/%m/%Y %H:%M:%S"), 16) except: disp.Dis_String(0, 17, payload, 16) +#Update display with info from camera (camera shooting new photo or name of the +# last photo) def on_message_camera(client, userdata, msg): - print(msg) - + pl = msg.payload.decode() + print("{} : {} ({})".format(msg.topic, pl, type(pl))) + if pl == "1" and msg.topic == camera_mqtt_topic + "/shooting" : + disp.Dis_String(0, 105, "Shooting photo... ", 16) + if msg.topic == camera_mqtt_topic + "/last_photo": + disp.Dis_String(0, 105, "Last: " + pl, 16) + #Callback de déconnexion au broker MQTT def on_disconnect(client, userdata, msg): if msg != 0: diff --git a/cameteo-interface/picam+mqtt.py b/cameteo-interface/picam+mqtt.py index 02f25ff..ed8dd94 100755 --- a/cameteo-interface/picam+mqtt.py +++ b/cameteo-interface/picam+mqtt.py @@ -1,59 +1,92 @@ #!/usr/bin/python3 +# -*- coding: utf-8 -*- +""" +Take a picture with the Pi Camera module and publish the path +and name of the file on a MQTT broker -# Take a picture with the Pi Camera module and publish the path -# and name of the file on a MQTT broker +@author: arofarn +""" import picamera import paho.mqtt.publish as mqtt from time import sleep -import datetime +from cameteo_conf import * - -# Camera settings -camera_resolution=(2592, 1944) -camera_warmup_time=2 #in seconds -#camera_iso=800 - -# MQTT settings -mqtt_server = 'localhost' -mqtt_port= 1883 -mqtt_auth= {'username':'cameteo', - 'password':'CaMeteo'} -mqtt_client_id= 'picamera2mqtt' -mqtt_qos=2 - -# Photo parameters -photo_path = '/home/pi/photos/' -photo_format = 'jpg' -photo_mqtt_topic = 'pi/picamera/' +mqtt_client_id = "picamera" ######## # Main # ######## -file_date = datetime.datetime.now().replace(microsecond=0).isoformat() -file_name = file_date + "." + photo_format +photo_extensions = {'jpeg': 'jpg', + 'png' : 'png', + 'gif': 'gif', + 'bmp': 'bmp', + 'yuv': 'yuv', + 'rgb': 'rgb', + 'rgba': 'rgba'} + +if not(os.path.exists(photo_dir)): + print("Create photos directory : " + photo_dir) + os.mkdir(photo_dir) + +file_name = datetime.strftime(datetime.now(), photo_name) + os.path.extsep + photo_extensions[photo_format] +file_path = os.path.join(photo_dir, file_name) + +print("Shooting " + file_path) # Taking a photo ################# + +# Tell the MQTT that we start shooting +mqtt.single(camera_mqtt_topic + "/shooting" , + payload= 1 , + qos= 1 , + retain= True , + hostname= mqtt_host , + port= mqtt_port , + client_id= mqtt_client_id , + auth= mqtt_auth ) + +# Camera settings cam = picamera.PiCamera(resolution = camera_resolution) +cam.iso = camera_iso +cam.awb_mode = camera_awb +cam.rotation = camera_rotation +cam.contrast = camera_contrast +cam.exposure_mode = camera_expo_mode +cam.image_effect = 'none' + +#Add some EXIF tags +cam.exif_tags['EXIF.UserComment'] = 'Cameteo !' # Warm-up cam.start_preview() sleep(camera_warmup_time) -print(photo_path+file_name) +cam.capture(file_path, format=photo_format, quality=95, thumbnail=None) -cam.capture(photo_path+file_name) +cam.close() # MQTT publication ################### -mqtt_data = [{'topic':photo_mqtt_topic+"path", 'payload':photo_path, 'qos':mqtt_qos, 'retain':False}, - {'topic':photo_mqtt_topic+"last_photo_name", 'payload':file_name, 'qos':mqtt_qos, 'retain':False}, - {'topic':photo_mqtt_topic+"last_photo_date", 'payload':file_date, 'qos':mqtt_qos, 'retain':False}] + +mqtt_data = [{'topic': camera_mqtt_topic + "/shooting", + 'payload': 0, + 'qos': 2, + 'retain': True}, + {'topic': camera_mqtt_topic + "/last_photo", + 'payload': file_name, + 'qos': 2, + 'retain': True}, + {'topic': camera_mqtt_topic + "/photos_path", + 'payload': photo_dir, + 'qos': 2, + 'retain': True}, + ] mqtt.multiple(mqtt_data, - hostname= mqtt_server , + hostname= mqtt_host , port= mqtt_port , client_id= mqtt_client_id , auth= mqtt_auth )