#!/usr/bin/python3 # -*- coding: UTF8 -*- # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ Display data from MQTT broker on ePaper screen @author: arofarn """ __version__ = 0.2 ########### # IMPORTS # ########### from cameteo_conf import * import paho.mqtt.client as mqtt import time import json import netifaces, socket import epd2in13 from PIL import Image from PIL import ImageDraw from PIL import ImageFont mqtt_client_id = "epaper_display" # Colors codes white = 255 black = 0 def update_epd(): """ Update ePaper Display """ #rotation de l'image de 90° + 180° si le paramètre epd_rotate est différent de 0 # la translation permet de rattraper un petit décalage en cas de rotation de 90+180° screen = image.rotate(90 + (epd_rotate * 180), expand=True, translate=(-6*epd_rotate, 0)) #Mis en memoire de l'image à afficher et affichage de l'image epd.set_frame_memory(screen, 0, 0) epd.display_frame() ############# # CALLBACKS # ############# def on_connect(client, userdata, flags, rc): """ Callback pour la connection au MQTT : souscriptions aux topics """ print(mqtt.connack_string(rc)) if rc == 0: print("Subscribing to %s ..." % mqtt_topic) client.subscribe([(mqtt_topic, 0), (camera_mqtt_topic + "/#", 0)] ) print("OK") def on_message(client, userdata, msg): """ Callback de gestion des messages arrivant au MQTT : affichage et enregistrement en base de données """ top=msg.topic[len(mqtt_topic)-1:].strip() subtopics = top.split("/") if subtopics[0] == "BME": payload = msg.payload.decode() val = json.loads(payload) #Test présence et cohérence de la valeur try: val['value'] = float(val['value'] ) except: print("Value error: {}".format(val['value'])) val['value'] = float('nan') #Gestion du symbole des degrés parfois difficile pour certaines sources val['unit'] = val['unit'].replace('deg', '°') #Affichage des données coord_type = { 'AT' : (12, 50), 'RH' : (137, 50), 'AP' : (12, 72), 'ALTI' : (137, 72), } print(val) if val['type'] in coord_type: #erase former text draw.rectangle(coord_type[val['type']] + (coord_type[val['type']][0] + 112, coord_type[val['type']][1] + 20), fill=white) #draw new values draw.text(coord_type[val['type']], "{:6.1f}{} ".format(val['value'], val['unit']), font=font20_bold, fill=black) update_epd() # Print feather's date and time on epaper display elif subtopics[0] == "SYS": payload = msg.payload.decode() val = json.loads(payload) if val['type'] == "TIME": try: #Mise en forme de la date et heure reçu pour fuseau horaire configuré dt_texte = datetime.strftime(datetime.strptime(val['value'], "%Y/%m/%d_%H:%M:%S") + TimeZone.utcoffset(None), "%d/%m/%Y %H:%M:%S") except: dt_texte = payload print(dt_texte) draw.rectangle((0, 34, epd2in13.EPD_HEIGHT, 48), fill=white) draw.text((0, 34), dt_texte, font=font14, fill=black) update_epd() def on_message_camera(client, userdata, msg): """ Update display with info from camera (camera shooting new photo or name of the last photo) """ pl = msg.payload.decode() print("{} : {} ({})".format(msg.topic, pl, type(pl))) # Photo en cours if pl == "1" and msg.topic == camera_mqtt_topic + "/shooting" : draw.rectangle((0, 106, epd2in13.EPD_HEIGHT, epd2in13.EPD_WIDTH), fill=white) draw.text((0, 106), "Shooting photo... ", font=font14, fill=black) update_epd() #Dernière photo prise if msg.topic == camera_mqtt_topic + "/last_photo": draw.rectangle((0, 106, epd2in13.EPD_HEIGHT, epd2in13.EPD_WIDTH), fill=white) draw.text((0, 106), "Last: " + pl, font=font14, fill=black) update_epd() def on_disconnect(client, userdata, msg): """ Callback de déconnexion au broker MQTT """ if msg != 0: print("Déconnexion imprévu : %s" % msg) exit() ######## # Main # ######## #Screen init. epd = epd2in13.EPD() epd.init(epd.lut_full_update) #List of TrueType fonts font12 = ImageFont.truetype(epd_font_file, 12) font14 = ImageFont.truetype(epd_font_file, 14) font16 = ImageFont.truetype(epd_font_file, 16) font20 = ImageFont.truetype(epd_font_file, 20) font12_bold = ImageFont.truetype(epd_bold_font_file, 12) font14_bold = ImageFont.truetype(epd_bold_font_file, 14) font16_bold = ImageFont.truetype(epd_bold_font_file, 16) font20_bold = ImageFont.truetype(epd_bold_font_file, 20) #font12_obl = ImageFont.truetype(epd_italic_font_file, 12) #font14_obl = ImageFont.truetype(epd_italic_font_file, 14) #font16_obl = ImageFont.truetype(epd_italic_font_file, 16) #New image buffer # Memo : 0=black, 255= white/blank image = Image.new('1', (epd2in13.EPD_HEIGHT, epd2in13.EPD_WIDTH), 255) draw = ImageDraw.Draw(image) #Draw basic text and frame : draw.rectangle((0, 0, epd2in13.EPD_HEIGHT, 18), fill=black) draw.text((60, 1), "Projet Camétéo", font=font16_bold, fill=white) draw.text((0, 19), "{} : IP= {}".format(socket.gethostname(), netifaces.ifaddresses('wlan0')[2][0]['addr']), font = font12, fill=black ) draw.line((0,49,epd2in13.EPD_HEIGHT, 49), fill=black) draw.line((0,71,epd2in13.EPD_HEIGHT, 71), fill=black) draw.line((0,93,epd2in13.EPD_HEIGHT, 93), fill=black) draw.line((125, 49, 125, 93), fill=black) #Display on ePaper screen epd.clear_frame_memory(0xFF) update_epd() # #screen = image.rotate(90, expand=True) #epd.set_frame_memory(screen, 0, 0) #epd.display_frame() #Toggle to partial refresh epd.init(epd.lut_partial_update) #Connect to MQTT broker and loop... mqtt_client = mqtt.Client(mqtt_client_id, clean_session=True) mqtt_client.username_pw_set(mqtt_user, mqtt_pass) mqtt_client.on_connect = on_connect mqtt_client.on_message = on_message mqtt_client.on_disconnect = on_disconnect #mqtt_client.message_callback_add("feather0/NTP/date", on_message_date) mqtt_client.message_callback_add(camera_mqtt_topic + "/#", on_message_camera) print(mqtt_host + ":" + str(mqtt_port)) mqtt_client.connect(mqtt_host, int(mqtt_port), 60) mqtt_client.loop_forever()