Nouveau driver ePaper Display de Waveshare supportant les Image de la librairie PIL
Beaucoup plus facile à utiliser pour de l'affichage riche
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -5,3 +5,4 @@ raspberry/pictures/* | ||||
| boitier/old* | ||||
| .directory | ||||
| *__pycache__* | ||||
| test* | ||||
|   | ||||
| @@ -20,7 +20,7 @@ | ||||
| #define MQTT_USERNAME    "arofarn" | ||||
| #define MQTT_KEY         "WaKaW9XMGUZ3rRJD" | ||||
| #define MQTT_ID          "huzzah0" | ||||
| #define MQTT_PUB_INTERVAL   10000 | ||||
| #define MQTT_PUB_INTERVAL   15000               // milliseconds | ||||
|  | ||||
| /************************* Time and NTP Setup *********************************/ | ||||
|  | ||||
| @@ -33,7 +33,7 @@ | ||||
|  | ||||
| #define MODE_STATION        true | ||||
| #define DEFAULT_ALTITUDE    140.0 | ||||
| #define DEFAULT_MSLP        1013.25   //Atmospheric Pressure at Sea-Level | ||||
| #define DEFAULT_MSLP        1013.25   //Mean Atmospheric Pressure at Mean Sea-Level | ||||
|  | ||||
| // Create an ESP8266 WiFiClient class to connect to the MQTT server. | ||||
| WiFiClient wifi_client; | ||||
| @@ -152,21 +152,11 @@ void loop() { | ||||
|     date_str = NTP.getTimeDateString(); | ||||
|     date_str.toCharArray(date_val,20); | ||||
|    | ||||
|     // Now we can publish stuff! | ||||
|     Serial.print(F("Sending date and time ")); | ||||
|     Serial.print(date_val); | ||||
|     Serial.print("..."); | ||||
|     if (! mqtt_client.publish("huzzah0/NTP/date", date_val, true, 2)) { | ||||
|       Serial.println(F("Failed")); | ||||
|     } else { | ||||
|       Serial.println(F("OK!")); | ||||
|     } | ||||
|    | ||||
|     // Now we can publish stuff! | ||||
|     Serial.print(F("Sending pressure value ")); | ||||
|     Serial.print(pressure_val); | ||||
|     Serial.print("..."); | ||||
|     val2json(pressure_val, date_str, "hPa", "PA").toCharArray(tosend, 120); | ||||
|     val2json(pressure_val, date_str, "hPa", "AP").toCharArray(tosend, 120); | ||||
|     if (! mqtt_client.publish("huzzah0/AdaBME280_1/pressure", tosend, true, 2) ) { | ||||
|       Serial.println(F("Failed")); | ||||
|     } else { | ||||
| @@ -182,7 +172,7 @@ void loop() { | ||||
|     Serial.print(F("Sending sea-level pressure value ")); | ||||
|     Serial.print(atm_press_sea_level); | ||||
|     Serial.print("..."); | ||||
|     val2json(atm_press_sea_level, date_str, "hPa", "SLPA").toCharArray(tosend, 120); | ||||
|     val2json(atm_press_sea_level, date_str, "hPa", "MSLP").toCharArray(tosend, 120); | ||||
|     if (! mqtt_client.publish("huzzah0/AdaBME280_1/sea_level_pressure", tosend, true, 2) ) { | ||||
|       Serial.println(F("Failed")); | ||||
|     } else { | ||||
| @@ -202,7 +192,7 @@ void loop() { | ||||
|     Serial.print(F("Sending humity value ")); | ||||
|     Serial.print(humidity_val); | ||||
|     Serial.print("..."); | ||||
|     val2json(humidity_val, date_str, "%", "HR").toCharArray(tosend, 120); | ||||
|     val2json(humidity_val, date_str, "%", "RH").toCharArray(tosend, 120); | ||||
|     if (! mqtt_client.publish("huzzah0/AdaBME280_1/humidity", tosend, true, 2)) { | ||||
|       Serial.println(F("Failed")); | ||||
|     } else { | ||||
| @@ -213,12 +203,22 @@ void loop() { | ||||
|     Serial.print(F("Sending temperature value ")); | ||||
|     Serial.print(temperature_val); | ||||
|     Serial.print("..."); | ||||
|     val2json(temperature_val, date_str, "degC", "TA").toCharArray(tosend, 120); | ||||
|     val2json(temperature_val, date_str, "degC", "AT").toCharArray(tosend, 120); | ||||
|     if (! mqtt_client.publish("huzzah0/AdaBME280_1/temperature", tosend, true, 2)) { | ||||
|       Serial.println(F("Failed")); | ||||
|     } else { | ||||
|       Serial.println(F("OK!")); | ||||
|     } | ||||
|  | ||||
|     // __LAST__ thing to send : Date and Time | ||||
|     Serial.print(F("Sending date and time ")); | ||||
|     Serial.print(date_val); | ||||
|     Serial.print("..."); | ||||
|     if (! mqtt_client.publish("huzzah0/NTP/date", date_val, true, 2)) { | ||||
|       Serial.println(F("Failed")); | ||||
|     } else { | ||||
|       Serial.println(F("OK!")); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   delay(10); | ||||
|   | ||||
| @@ -32,5 +32,11 @@ photo_dir=/home/pi/Cameteo/photos/ | ||||
| photo_name=test_%%Y%%m%%d_%%H%%M%%S | ||||
| photo_format=jpeg | ||||
|  | ||||
| [EPD] | ||||
| epd_font_file=/usr/share/fonts/truetype/freefont/FreeMono.ttf | ||||
| epd_bold_font_file=/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf | ||||
| epd_italic_font_file=/usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf | ||||
| epd_rotate = 1 | ||||
|  | ||||
| [MISC] | ||||
| TimeZone=2 | ||||
|   | ||||
| @@ -72,3 +72,9 @@ photo_extensions = {'jpeg': 'jpg', | ||||
|                     'yuv': 'yuv', | ||||
|                     'rgb': 'rgb', | ||||
|                     'rgba': 'rgba'} | ||||
|  | ||||
| #epaper display | ||||
| epd_font_file           =  parser['EPD'].get('epd_font_file'        , fallback='/usr/share/fonts/truetype/freefont/FreeMono.ttf') | ||||
| epd_bold_font_file      =  parser['EPD'].get('epd_bold_font_file'   , fallback='/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf') | ||||
| epd_italic_font_file    =  parser['EPD'].get('epd_italic_font_file' , fallback='/usr/share/fonts/truetype/freefont/FreeMonoOblique.ttf') | ||||
| epd_rotate              =  min(int(parser['EPD'].get('epd_rotate', fallback=0)), 1) | ||||
| @@ -29,7 +29,7 @@ from PIL import Image | ||||
| import RPi.GPIO as GPIO | ||||
|  | ||||
| # Display resolution | ||||
| EPD_WIDTH       = 122 | ||||
| EPD_WIDTH       = 128 | ||||
| EPD_HEIGHT      = 250 | ||||
|  | ||||
| # EPD2IN13 commands | ||||
| @@ -127,7 +127,7 @@ class EPD: | ||||
|  | ||||
|     def wait_until_idle(self): | ||||
|         while(self.digital_read(self.busy_pin) == 1):      # 0: idle, 1: busy | ||||
|             self.delay_ms(100) | ||||
|             self.delay_ms(20) | ||||
| ## | ||||
|  #  @brief: module reset. | ||||
|  #          often used to awaken the module in deep sleep, | ||||
| @@ -214,7 +214,7 @@ class EPD: | ||||
|         self.set_memory_pointer(0, 0) | ||||
|         self.send_command(WRITE_RAM) | ||||
|         # send the color data | ||||
|         for i in range(0, self.width / 8 * self.height): | ||||
|         for i in range(0, int(self.width / 8 * self.height)): | ||||
|             self.send_data(color) | ||||
|  | ||||
| ## | ||||
|   | ||||
| @@ -11,13 +11,24 @@ Display data from MQTT broker on ePaper screen | ||||
|  | ||||
| from cameteo_conf import * | ||||
| import paho.mqtt.client as mqtt | ||||
| from spidev import SpiDev | ||||
| import EPD_driver | ||||
| import time | ||||
| import json | ||||
| import netifaces | ||||
| import netifaces, socket | ||||
| import epd2in13 | ||||
| from PIL import Image | ||||
| from PIL import ImageDraw | ||||
| from PIL import ImageFont | ||||
|  | ||||
| mqtt_client_id = "epaper_display" | ||||
|  | ||||
| def update_epd(): | ||||
|     #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 # | ||||
| ############# | ||||
| @@ -51,35 +62,57 @@ def on_message(client, userdata, msg): | ||||
|             val['value'] = float('nan') | ||||
|          | ||||
|         #Gestion du symbole des degrés parfois difficile pour certaines sources | ||||
|         #val['unit'] = val['unit'].replace('deg', '°') | ||||
|         val['unit'] = val['unit'].replace('deg', '°') | ||||
|          | ||||
|         #Affichage des données | ||||
|         coord_type = { 'TA' : 33, | ||||
|                        'HR' : 49, | ||||
|                        'SLPA' : 65 | ||||
|                        } | ||||
|         coord_type = { 'AT'     : (2, 50), | ||||
|                        'RH'     : (127, 50), | ||||
|                        'MSLP'   : (2, 66), | ||||
|                        'ALTI'   : (127, 66),  | ||||
|                       } | ||||
|         if val['type'] in coord_type: | ||||
|             disp.Dis_String(125, coord_type[val['type']], "{} {}  ".format(val['value'], val['unit']), 16) | ||||
|             #erase former text | ||||
|             draw.rectangle(coord_type[val['type']] + (coord_type[val['type']][0] + 122, coord_type[val['type']][1] + 14), fill=255) | ||||
|             #draw new values             | ||||
|             draw.text(coord_type[val['type']], "{:8.1f} {}  ".format(val['value'], val['unit']), font=font14, fill=0) | ||||
| #            #Update the display             | ||||
| #            screen = image.rotate(90, expand=True) | ||||
| #            epd.set_frame_memory(screen, 0, 0) | ||||
| #            epd.display_frame() | ||||
|      | ||||
| #Callback managing date and time from MQTT broker  | ||||
| def on_message_date(client, userdata, msg): | ||||
|     payload = msg.payload.decode() | ||||
|     print("Date : " + payload) | ||||
|      | ||||
|     try: | ||||
|         d = datetime.strptime(payload, "%H:%M:%S %d/%m/%Y") | ||||
|         disp.Dis_String(0, 17, datetime.strftime(d + TimeZone.utcoffset(None), "%d/%m/%Y %H:%M:%S"), 16) | ||||
|         #Mise en forme de la date et heure reçu pour fuseau horaire configuré | ||||
|         dt_texte = datetime.strftime(datetime.strptime(payload, "%H:%M:%S %d/%m/%Y") + TimeZone.utcoffset(None), "%d/%m/%Y %H:%M:%S") | ||||
|     except: | ||||
|         disp.Dis_String(0, 17, payload, 16) | ||||
|         dt_texte = payload | ||||
|      | ||||
|     #Affichage du résultat | ||||
|     draw.rectangle((0, 34, epd2in13.EPD_HEIGHT, 48), fill=255)     | ||||
|     draw.text((0, 34), dt_texte, font=font14, fill=0) | ||||
|     update_epd() | ||||
|  | ||||
| #Update display with info from camera (camera shooting new photo or name of the | ||||
| # last photo) | ||||
| def on_message_camera(client, userdata, msg): | ||||
|     pl = msg.payload.decode() | ||||
|     print("{} : {} ({})".format(msg.topic, pl, type(pl)))     | ||||
|      | ||||
|     # Photo en cours | ||||
|     if pl == "1" and msg.topic == camera_mqtt_topic + "/shooting" : | ||||
|         disp.Dis_String(0, 105, "Shooting photo...              ", 16) | ||||
|         draw.rectangle((0, 105, epd2in13.EPD_HEIGHT, 120), fill=255) | ||||
|         draw.text((0, 105), "Shooting photo...              ", font=font14, fill=0) | ||||
|         update_epd() | ||||
|      | ||||
|     #Dernière photo prise | ||||
|     if msg.topic == camera_mqtt_topic + "/last_photo": | ||||
|         disp.Dis_String(0, 105, "Last: " + pl, 16) | ||||
|         draw.rectangle((0, 105, epd2in13.EPD_HEIGHT, 120), fill=255) | ||||
|         draw.text((0, 105), "Last: " + pl, font=font14, fill=0) | ||||
|         update_epd() | ||||
|  | ||||
| #Callback de déconnexion au broker MQTT | ||||
| def on_disconnect(client, userdata, msg): | ||||
| @@ -91,21 +124,46 @@ def on_disconnect(client, userdata, msg): | ||||
| # Main # | ||||
| ######## | ||||
|  | ||||
| #init and Clear full screen | ||||
| bus = 0  | ||||
| device = 0 | ||||
| disp = EPD_driver.EPD_driver(spi=SpiDev(bus, device)) | ||||
| #Screen init. | ||||
| epd = epd2in13.EPD() | ||||
| epd.init(epd.lut_full_update) | ||||
|  | ||||
| print("Start display...") | ||||
| disp.Dis_Clear_full() | ||||
| disp.Dis_Clear_part() | ||||
| print("OK") | ||||
| #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) | ||||
| 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) | ||||
| #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) | ||||
|  | ||||
| #disp.Dis_String(0, 0, "{} | {}".format(socket.gethostname(), netifaces.ifaddresses('wlan0')[2][0]['addr']), 12) | ||||
| disp.Dis_String(0, 0,  "IPv4         : {}".format(netifaces.ifaddresses('wlan0')[2][0]['addr']), 16) | ||||
| disp.Dis_String(0, 33, "Temperature  : ", 16) | ||||
| disp.Dis_String(0, 49, "Humidity     : ", 16) | ||||
| disp.Dis_String(0, 65, "Sea Pression : ", 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=0) | ||||
| draw.text((60, 2), "Projet Camétéo", font=font16_bold, fill=255) | ||||
| draw.text((0, 20), "{} : IP= {}".format(socket.gethostname(), netifaces.ifaddresses('wlan0')[2][0]['addr']), font = font12, fill=0 ) | ||||
| draw.line((0,49,epd2in13.EPD_HEIGHT, 49), fill=0) | ||||
| draw.line((0,65,epd2in13.EPD_HEIGHT, 65), fill=0) | ||||
| draw.line((0,81,epd2in13.EPD_HEIGHT, 81), fill=0) | ||||
| draw.line((125, 49, 125, 81), fill=0) | ||||
|  | ||||
| #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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user