From 90a20d2a877553d8c6a10ae51017f44dd572c372 Mon Sep 17 00:00:00 2001 From: TheYOSH Date: Sun, 13 Jan 2019 16:52:38 +0100 Subject: [PATCH] Add support for more OLED displays. #232, #193 --- install.sh | 9 +- locales/en_US/LC_MESSAGES/terrariumpi.mo | Bin 77752 -> 77446 bytes locales/en_US/LC_MESSAGES/terrariumpi.po | 97 ++--- locales/terrariumpi.pot | 91 ++--- static/js/terrariumpi.js | 21 ++ terrariumDisplay.py | 437 ++++++++++++++--------- terrariumEngine.py | 2 +- terrariumNotification.py | 30 +- terrariumTranslations.py | 2 +- views/notifications.tpl | 21 +- 10 files changed, 407 insertions(+), 303 deletions(-) diff --git a/install.sh b/install.sh index 0ee31dd3f..4c9615923 100755 --- a/install.sh +++ b/install.sh @@ -47,12 +47,13 @@ case $? in 0) whiptail --backtitle "${INSTALLER_TITLE}" --title " TerrariumPI Installer " --infobox "TerrariumPI is removing not needed programs" 0 0 debconf-apt-progress -- apt-get -y remove wolfram-engine sonic-pi oracle-java8-jdk desktop-base gnome-desktop3-data libgnome-desktop-3-10 epiphany-browser-data epiphany-browser nuscratch scratch wiringpi "^libreoffice.*" - # Remove previous python 2.X packages to make sure pip installed libraries are used - debconf-apt-progress -- apt-get -y remove owhttpd owftpd python-gpiozero python-dateutil python-imaging python-ow python-picamera python-pigpio python-psutil python-requests python-rpi.gpio debconf-apt-progress -- apt-get -y autoremove ;; esac +# Remove previous python 2.X packages to make sure pip installed libraries are used +debconf-apt-progress -- apt-get -y remove owhttpd owftpd python-gpiozero python-dateutil python-imaging python-ow python-picamera python-pigpio python-psutil python-requests python-rpi.gpio + # Install required packages to get the terrarium software running PYTHON_LIBS="" if [ $PYTHON -eq 2 ]; then @@ -63,7 +64,7 @@ fi debconf-apt-progress -- apt-get -y update debconf-apt-progress -- apt-get -y full-upgrade -debconf-apt-progress -- apt-get -y install libftdi1 screen git subversion watchdog build-essential i2c-tools pigpio owserver sqlite3 vlc-nox ffmpeg libasound2-dev sispmctl lshw libffi-dev ntp libglib2.0-dev rng-tools libcblas3 libatlas3-base libjasper1 libgstreamer0.10-0 libgstreamer1.0-0 libilmbase12 libopenexr22 libgtk-3-0 libxml2-dev libxslt1-dev python-twisted $PYTHON_LIBS +debconf-apt-progress -- apt-get -y install libftdi1 screen git subversion watchdog build-essential i2c-tools pigpio owserver sqlite3 vlc-nox ffmpeg libfreetype6-dev libjpeg-dev libasound2-dev sispmctl lshw libffi-dev ntp libglib2.0-dev rng-tools libcblas3 libatlas3-base libjasper1 libgstreamer0.10-0 libgstreamer1.0-0 libilmbase12 libopenexr22 libgtk-3-0 libxml2-dev libxslt1-dev python-twisted $PYTHON_LIBS PROGRESS=35 # Update submodules if downloaded through tar or zip @@ -97,7 +98,7 @@ EOF git submodule update > /dev/null cd "${BASEDIR}/.." -PIP_MODULES="python-dateutil rpi.gpio psutil picamera pigpio requests gpiozero gevent untangle uptime bottle bottle_websocket pylibftdi pyalsaaudio pyserial python-twitter python-pushover requests[socks] Adafruit_DHT Adafruit_SSD1306 Adafruit_SHT31 bluepy pywemo pyownet emails" +PIP_MODULES="python-dateutil rpi.gpio psutil picamera pigpio requests gpiozero gevent untangle uptime bottle bottle_websocket pylibftdi pyalsaaudio pyserial python-twitter python-pushover requests[socks] Adafruit_DHT Adafruit_SHT31 luma.oled bluepy pywemo pyownet emails" if [ $PYTHON -eq 3 ]; then PIP_MODULES="${PIP_MODULES} opencv-python-headless" fi diff --git a/locales/en_US/LC_MESSAGES/terrariumpi.mo b/locales/en_US/LC_MESSAGES/terrariumpi.mo index da0ad169f3c61285350f7734cb6d8e68e99c8e33..b0c6b6ca1dbd71ccfce7d19509bc45266b63dce4 100644 GIT binary patch delta 15856 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, 2016-2018. +# Copyright (C) 2016-2019 TheYOSH +# Joshua (TheYOSH) Rubingh, , 2016-2019. # msgid "" msgstr "" "Project-Id-Version: TerrariumPI 3.9.3\n" -"POT-Creation-Date: 2018-12-28 14:27+CET\n" -"PO-Revision-Date: 2018-12-28 14:27+0100\n" +"POT-Creation-Date: 2019-01-13 16:33+CET\n" +"PO-Revision-Date: 2019-01-13 16:34+0100\n" "Last-Translator: Joshua (TheYOSH) Rubingh \n" "Language-Team: \n" "Language: en_US\n" @@ -365,12 +365,12 @@ msgid "Holds the password for authentication with the mailserver if needed." msgstr "Holds the password for authentication with the mailserver if needed." #: terrariumTranslations.py:125 -msgid "Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus." -msgstr "Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus." +msgid "Holds the display chip that is used." +msgstr "Holds the display chip that is used." #: terrariumTranslations.py:126 -msgid "Holds the LCD screen resolution." -msgstr "Holds the LCD screen resolution." +msgid "Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus." +msgstr "Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus." #: terrariumTranslations.py:127 msgid "Reserve first LCD line for static title." @@ -758,7 +758,7 @@ msgid "Files" msgstr "Files" #: views/audio_playlist.tpl:48 views/door_settings.tpl:36 -#: views/notifications.tpl:278 views/profile.tpl:179 +#: views/notifications.tpl:275 views/profile.tpl:179 #: views/sensor_settings.tpl:57 views/switch_settings.tpl:72 #: views/system_environment.tpl:1801 views/system_settings.tpl:189 #: views/webcam_settings.tpl:48 @@ -829,9 +829,9 @@ msgstr "Calendar" #: views/inc/usage_weather.tpl:94 views/inc/usage_webcams.tpl:46 #: views/inc/usage_webcams.tpl:88 views/inc/usage_webcams.tpl:163 #: views/notifications.tpl:27 views/notifications.tpl:64 -#: views/notifications.tpl:104 views/notifications.tpl:137 -#: views/notifications.tpl:162 views/notifications.tpl:191 -#: views/notifications.tpl:212 views/switch_status.tpl:37 +#: views/notifications.tpl:101 views/notifications.tpl:134 +#: views/notifications.tpl:159 views/notifications.tpl:188 +#: views/notifications.tpl:209 views/switch_status.tpl:37 #: views/system_environment.tpl:27 views/system_environment.tpl:158 #: views/system_environment.tpl:370 views/system_environment.tpl:581 #: views/system_environment.tpl:792 views/system_environment.tpl:1003 @@ -904,7 +904,7 @@ msgstr "mode" #: views/inc/usage_environment.tpl:25 views/inc/usage_environment.tpl:121 #: views/inc/usage_environment.tpl:129 views/inc/usage_environment.tpl:213 #: views/inc/usage_environment.tpl:221 views/inc/usage_environment.tpl:307 -#: views/inc/usage_environment.tpl:315 views/notifications.tpl:92 +#: views/inc/usage_environment.tpl:315 views/notifications.tpl:89 #: views/switch_settings.tpl:147 views/system_environment.tpl:41 #: views/system_environment.tpl:172 views/system_environment.tpl:384 #: views/system_environment.tpl:595 views/system_environment.tpl:806 @@ -1168,9 +1168,9 @@ msgstr "Here you can configure your doors." #: views/hardware.tpl:30 views/inc/menu.tpl:159 views/inc/usage_doors.tpl:98 #: views/inc/usage_doors.tpl:119 views/inc/usage_sensors.tpl:109 #: views/inc/usage_sensors.tpl:165 views/inc/usage_switches.tpl:103 -#: views/inc/usage_switches.tpl:134 views/sensor_settings.tpl:19 -#: views/sensor_settings.tpl:100 views/switch_settings.tpl:19 -#: views/switch_settings.tpl:106 +#: views/inc/usage_switches.tpl:134 views/notifications.tpl:74 +#: views/sensor_settings.tpl:19 views/sensor_settings.tpl:100 +#: views/switch_settings.tpl:19 views/switch_settings.tpl:106 msgid "Hardware" msgstr "Hardware" @@ -1178,8 +1178,9 @@ msgstr "Hardware" #: views/inc/usage_doors.tpl:106 views/inc/usage_doors.tpl:122 #: views/inc/usage_sensors.tpl:123 views/inc/usage_sensors.tpl:168 #: views/inc/usage_switches.tpl:112 views/inc/usage_switches.tpl:137 -#: views/sensor_settings.tpl:22 views/sensor_settings.tpl:125 -#: views/switch_settings.tpl:22 views/switch_settings.tpl:125 +#: views/notifications.tpl:81 views/sensor_settings.tpl:22 +#: views/sensor_settings.tpl:125 views/switch_settings.tpl:22 +#: views/switch_settings.tpl:125 msgid "Address" msgstr "Address" @@ -1707,7 +1708,7 @@ msgstr "With the wrench you will get an options menu." #: views/inc/usage_sensors.tpl:17 views/inc/usage_sensors.tpl:203 #: views/inc/usage_switches.tpl:13 views/inc/usage_switches.tpl:160 #: views/inc/usage_webcams.tpl:13 views/inc/usage_webcams.tpl:154 -#: views/notifications.tpl:88 views/notifications.tpl:226 +#: views/notifications.tpl:85 views/notifications.tpl:223 msgid "Title" msgstr "Title" @@ -1808,7 +1809,7 @@ msgstr "All fields with a %s are required." #: views/inc/usage_environment.tpl:25 views/inc/usage_environment.tpl:121 #: views/inc/usage_environment.tpl:129 views/inc/usage_environment.tpl:213 #: views/inc/usage_environment.tpl:221 views/inc/usage_environment.tpl:307 -#: views/inc/usage_environment.tpl:315 views/notifications.tpl:91 +#: views/inc/usage_environment.tpl:315 views/notifications.tpl:88 #: views/switch_settings.tpl:146 msgid "Enabled" msgstr "Enabled" @@ -2322,95 +2323,75 @@ msgstr "SMTP password" msgid "Display" msgstr "Display" -#: views/notifications.tpl:74 -msgid "I2C address" -msgstr "I2C address" - -#: views/notifications.tpl:78 -msgid "Screen resolution" -msgstr "Screen resolution" - -#: views/notifications.tpl:81 -msgid "LCD 16 Characters, 2 Lines" -msgstr "LCD 16 Characters, 2 Lines" - -#: views/notifications.tpl:82 -msgid "LCD 20 Characters, 4 Lines" -msgstr "LCD 20 Characters, 4 Lines" - -#: views/notifications.tpl:83 -msgid "OLED 128 x 64 pixels" -msgstr "OLED 128 x 64 pixels" - -#: views/notifications.tpl:104 +#: views/notifications.tpl:101 msgid "Twitter" msgstr "Twitter" -#: views/notifications.tpl:114 +#: views/notifications.tpl:111 msgid "Consumer key" msgstr "Consumer key" -#: views/notifications.tpl:118 +#: views/notifications.tpl:115 msgid "Consumer secret" msgstr "Consumer secret" -#: views/notifications.tpl:122 +#: views/notifications.tpl:119 msgid "Access token" msgstr "Access token" -#: views/notifications.tpl:126 +#: views/notifications.tpl:123 msgid "Access token secret" msgstr "Access token secret" -#: views/notifications.tpl:137 +#: views/notifications.tpl:134 msgid "Pushover" msgstr "Pushover" -#: views/notifications.tpl:147 +#: views/notifications.tpl:144 msgid "API Token" msgstr "API Token" -#: views/notifications.tpl:151 +#: views/notifications.tpl:148 msgid "User key" msgstr "User key" -#: views/notifications.tpl:162 +#: views/notifications.tpl:159 msgid "Telegram" msgstr "Telegram" -#: views/notifications.tpl:172 +#: views/notifications.tpl:169 msgid "Bot Token" msgstr "Bot Token" -#: views/notifications.tpl:176 +#: views/notifications.tpl:173 msgid "Username" msgstr "Username" -#: views/notifications.tpl:180 +#: views/notifications.tpl:177 msgid "Proxy" msgstr "Proxy" -#: views/notifications.tpl:191 +#: views/notifications.tpl:188 msgid "Webhook" msgstr "Webhook" -#: views/notifications.tpl:201 +#: views/notifications.tpl:198 msgid "Full post url" msgstr "Full post url" -#: views/notifications.tpl:212 +#: views/notifications.tpl:209 msgid "Messages" msgstr "Messages" -#: views/notifications.tpl:223 +#: views/notifications.tpl:220 msgid "Trigger" msgstr "Trigger" -#: views/notifications.tpl:229 +#: views/notifications.tpl:226 msgid "Message" msgstr "Message" -#: views/notifications.tpl:232 +#: views/notifications.tpl:229 msgid "Service" msgstr "Service" diff --git a/locales/terrariumpi.pot b/locales/terrariumpi.pot index b0e64da24..b3436a2ed 100644 --- a/locales/terrariumpi.pot +++ b/locales/terrariumpi.pot @@ -1,11 +1,11 @@ # SOME DESCRIPTIVE TITLE. -# Copyright (C) 2016-2018 TheYOSH -# Joshua (TheYOSH) Rubingh, , 2016-2018. +# Copyright (C) 2016-2019 TheYOSH +# Joshua (TheYOSH) Rubingh, , 2016-2019. # msgid "" msgstr "" "Project-Id-Version: TerrariumPI 3.9.3\n" -"POT-Creation-Date: 2018-12-28 14:27+CET\n" +"POT-Creation-Date: 2019-01-13 16:33+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -364,11 +364,11 @@ msgid "Holds the password for authentication with the mailserver if needed." msgstr "" #: terrariumTranslations.py:125 -msgid "Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus." +msgid "Holds the display chip that is used." msgstr "" #: terrariumTranslations.py:126 -msgid "Holds the LCD screen resolution." +msgid "Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus." msgstr "" #: terrariumTranslations.py:127 @@ -757,7 +757,7 @@ msgid "Files" msgstr "" #: views/audio_playlist.tpl:48 views/door_settings.tpl:36 -#: views/notifications.tpl:278 views/profile.tpl:179 +#: views/notifications.tpl:275 views/profile.tpl:179 #: views/sensor_settings.tpl:57 views/switch_settings.tpl:72 #: views/system_environment.tpl:1801 views/system_settings.tpl:189 #: views/webcam_settings.tpl:48 @@ -828,9 +828,9 @@ msgstr "" #: views/inc/usage_weather.tpl:94 views/inc/usage_webcams.tpl:46 #: views/inc/usage_webcams.tpl:88 views/inc/usage_webcams.tpl:163 #: views/notifications.tpl:27 views/notifications.tpl:64 -#: views/notifications.tpl:104 views/notifications.tpl:137 -#: views/notifications.tpl:162 views/notifications.tpl:191 -#: views/notifications.tpl:212 views/switch_status.tpl:37 +#: views/notifications.tpl:101 views/notifications.tpl:134 +#: views/notifications.tpl:159 views/notifications.tpl:188 +#: views/notifications.tpl:209 views/switch_status.tpl:37 #: views/system_environment.tpl:27 views/system_environment.tpl:158 #: views/system_environment.tpl:370 views/system_environment.tpl:581 #: views/system_environment.tpl:792 views/system_environment.tpl:1003 @@ -903,7 +903,7 @@ msgstr "" #: views/inc/usage_environment.tpl:25 views/inc/usage_environment.tpl:121 #: views/inc/usage_environment.tpl:129 views/inc/usage_environment.tpl:213 #: views/inc/usage_environment.tpl:221 views/inc/usage_environment.tpl:307 -#: views/inc/usage_environment.tpl:315 views/notifications.tpl:92 +#: views/inc/usage_environment.tpl:315 views/notifications.tpl:89 #: views/switch_settings.tpl:147 views/system_environment.tpl:41 #: views/system_environment.tpl:172 views/system_environment.tpl:384 #: views/system_environment.tpl:595 views/system_environment.tpl:806 @@ -1167,9 +1167,9 @@ msgstr "" #: views/hardware.tpl:30 views/inc/menu.tpl:159 views/inc/usage_doors.tpl:98 #: views/inc/usage_doors.tpl:119 views/inc/usage_sensors.tpl:109 #: views/inc/usage_sensors.tpl:165 views/inc/usage_switches.tpl:103 -#: views/inc/usage_switches.tpl:134 views/sensor_settings.tpl:19 -#: views/sensor_settings.tpl:100 views/switch_settings.tpl:19 -#: views/switch_settings.tpl:106 +#: views/inc/usage_switches.tpl:134 views/notifications.tpl:74 +#: views/sensor_settings.tpl:19 views/sensor_settings.tpl:100 +#: views/switch_settings.tpl:19 views/switch_settings.tpl:106 msgid "Hardware" msgstr "" @@ -1177,8 +1177,9 @@ msgstr "" #: views/inc/usage_doors.tpl:106 views/inc/usage_doors.tpl:122 #: views/inc/usage_sensors.tpl:123 views/inc/usage_sensors.tpl:168 #: views/inc/usage_switches.tpl:112 views/inc/usage_switches.tpl:137 -#: views/sensor_settings.tpl:22 views/sensor_settings.tpl:125 -#: views/switch_settings.tpl:22 views/switch_settings.tpl:125 +#: views/notifications.tpl:81 views/sensor_settings.tpl:22 +#: views/sensor_settings.tpl:125 views/switch_settings.tpl:22 +#: views/switch_settings.tpl:125 msgid "Address" msgstr "" @@ -1706,7 +1707,7 @@ msgstr "" #: views/inc/usage_sensors.tpl:17 views/inc/usage_sensors.tpl:203 #: views/inc/usage_switches.tpl:13 views/inc/usage_switches.tpl:160 #: views/inc/usage_webcams.tpl:13 views/inc/usage_webcams.tpl:154 -#: views/notifications.tpl:88 views/notifications.tpl:226 +#: views/notifications.tpl:85 views/notifications.tpl:223 msgid "Title" msgstr "" @@ -1807,7 +1808,7 @@ msgstr "" #: views/inc/usage_environment.tpl:25 views/inc/usage_environment.tpl:121 #: views/inc/usage_environment.tpl:129 views/inc/usage_environment.tpl:213 #: views/inc/usage_environment.tpl:221 views/inc/usage_environment.tpl:307 -#: views/inc/usage_environment.tpl:315 views/notifications.tpl:91 +#: views/inc/usage_environment.tpl:315 views/notifications.tpl:88 #: views/switch_settings.tpl:146 msgid "Enabled" msgstr "" @@ -2321,95 +2322,75 @@ msgstr "" msgid "Display" msgstr "" -#: views/notifications.tpl:74 -msgid "I2C address" -msgstr "" - -#: views/notifications.tpl:78 -msgid "Screen resolution" -msgstr "" - -#: views/notifications.tpl:81 -msgid "LCD 16 Characters, 2 Lines" -msgstr "" - -#: views/notifications.tpl:82 -msgid "LCD 20 Characters, 4 Lines" -msgstr "" - -#: views/notifications.tpl:83 -msgid "OLED 128 x 64 pixels" -msgstr "" - -#: views/notifications.tpl:104 +#: views/notifications.tpl:101 msgid "Twitter" msgstr "" -#: views/notifications.tpl:114 +#: views/notifications.tpl:111 msgid "Consumer key" msgstr "" -#: views/notifications.tpl:118 +#: views/notifications.tpl:115 msgid "Consumer secret" msgstr "" -#: views/notifications.tpl:122 +#: views/notifications.tpl:119 msgid "Access token" msgstr "" -#: views/notifications.tpl:126 +#: views/notifications.tpl:123 msgid "Access token secret" msgstr "" -#: views/notifications.tpl:137 +#: views/notifications.tpl:134 msgid "Pushover" msgstr "" -#: views/notifications.tpl:147 +#: views/notifications.tpl:144 msgid "API Token" msgstr "" -#: views/notifications.tpl:151 +#: views/notifications.tpl:148 msgid "User key" msgstr "" -#: views/notifications.tpl:162 +#: views/notifications.tpl:159 msgid "Telegram" msgstr "" -#: views/notifications.tpl:172 +#: views/notifications.tpl:169 msgid "Bot Token" msgstr "" -#: views/notifications.tpl:176 +#: views/notifications.tpl:173 msgid "Username" msgstr "" -#: views/notifications.tpl:180 +#: views/notifications.tpl:177 msgid "Proxy" msgstr "" -#: views/notifications.tpl:191 +#: views/notifications.tpl:188 msgid "Webhook" msgstr "" -#: views/notifications.tpl:201 +#: views/notifications.tpl:198 msgid "Full post url" msgstr "" -#: views/notifications.tpl:212 +#: views/notifications.tpl:209 msgid "Messages" msgstr "" -#: views/notifications.tpl:223 +#: views/notifications.tpl:220 msgid "Trigger" msgstr "" -#: views/notifications.tpl:229 +#: views/notifications.tpl:226 msgid "Message" msgstr "" -#: views/notifications.tpl:232 +#: views/notifications.tpl:229 msgid "Service" msgstr "" diff --git a/static/js/terrariumpi.js b/static/js/terrariumpi.js index f0362f88d..376b1758e 100644 --- a/static/js/terrariumpi.js +++ b/static/js/terrariumpi.js @@ -2770,6 +2770,27 @@ function uploadProfileImage() { } /* End profile code */ +/** + * Sort values alphabetically in select + * source: http://stackoverflow.com/questions/12073270/sorting-options-elements-alphabetically-using-jquery + */ +$.fn.extend({ + sortSelect() { + let options = this.find("option"), + arr = options.map(function(_, o) { return { t: $(o).text(), v: o.value }; }).get(); + + arr.sort((o1, o2) => { // sort select + let t1 = o1.t.toLowerCase(), + t2 = o2.t.toLowerCase(); + return t1 > t2 ? 1 : t1 < t2 ? -1 : 0; + }); + + options.each((i, o) => { + o.value = arr[i].v; + $(o).text(arr[i].t); + }); + } +}); // Start it all..... $(document).ready(function() { diff --git a/terrariumDisplay.py b/terrariumDisplay.py index 2611354b6..e11280855 100644 --- a/terrariumDisplay.py +++ b/terrariumDisplay.py @@ -17,14 +17,19 @@ import smbus import time import datetime +import math +import textwrap try: import thread as _thread except ImportError as ex: import _thread import serial -import Adafruit_SSD1306 -from PIL import Image, ImageDraw, ImageFont +from hashlib import md5 +from PIL import Image, ImageFont +from luma.core.interface.serial import i2c +from luma.core.render import canvas +from luma.oled.device import ssd1306, ssd1309, ssd1322, ssd1325, ssd1327, ssd1331, ssd1351, sh1106 from terrariumUtils import terrariumUtils @@ -183,39 +188,36 @@ def lcd_load_custom_chars(self, fontdata): self.lcd_write_char(line) class terrariumScreen(object): + TYPE = None - __MAX_SHOW_LINE_TIMEOUT = 7 - __MAX_SHOW_CHAR_TIMEOUT = 0.01 - - def __init__(self,id,address,name,resolution = '16x2',title = False): - self.id = id + def __init__(self, display_id, address, name, title = False): + self.display_id = display_id + self.resolution = [0,0] self.font_size = 1 self.animating = False self.set_name(name) - self.set_resolution(resolution) self.set_title(title) self.set_address(address) self.loading() - def loading(self): - self.message('Starting TerrariumPI') + def get_type(self): + return self.TYPE - def clear(self): - pass + def get_id(self): + if self.display_id in [None,'None','']: + self.display_id = md5((self.get_type() + self.get_address()).encode('utf-8')).hexdigest() - def write_image(self,imagefile): - pass + return self.display_id - def get_max_chars(self): - return int(float(self.resolution[0]) / float(self.font_size)) - - def get_max_lines(self): - return int(float(self.resolution[1]) / float(self.font_size)) + def set_name(self,value): + self.name = None + if value is not None and '' != value: + self.name = value - def get_id(self): - return self.id + def get_name(self): + return self.name def set_address(self,address): self.address = None @@ -226,198 +228,220 @@ def set_address(self,address): self.bus = 1 if len(address) == 1 else address[1] def get_address(self): - data = str(self.address) + data = self.address if self.bus is not None: data = data + ',' + str(self.bus) return data - def set_name(self,value): - self.name = None - if value is not None and '' != value: - self.name = value - - def get_name(self): - return self.name - - def set_resolution(self,resolution): - self.resolution = None - if resolution is not None and '' != resolution: - self.resolution = resolution.split('x') - - def get_resolution(self): - if self.resolution is not None: - return 'x'.join(self.resolution) - - return '' - def set_title(self,value): self.title = terrariumUtils.is_true(value) def get_title(self): - return self.title == True + return terrariumUtils.is_true(self.title) def get_config(self): - data = {'id' : self.get_id(), - 'address' : self.get_address(), - 'name' : self.get_name(), - 'resolution' : self.get_resolution(), - 'title' : self.get_title()} + data = {'id' : self.get_id(), + 'address' : self.get_address(), + 'name' : self.get_name(), + 'title' : self.get_title(), + 'hardwaretype': self.get_type(), + 'supported' : terrariumDisplay.valid_hardware_types()} return data - def message(self,messages): - if self.animating: - return + def loading(self): + self.message('Starting TerrariumPI') - if isinstance(messages,str): - if len(messages) > 2 * self.get_max_chars(): - # Split long messages on a 'dot', creating multiple lines - messages = messages.split('. ') - if len(messages) == 1: - # When it is one long sentence, split it in have on a space - splitpos = messages[0].find(' ',len(messages[0])/2) - messages = [messages[0][:splitpos].strip(),messages[0][splitpos:].strip()] - - else: - messages = [messages.strip()] - - # Set 'now' timestamp - self.messages = [datetime.datetime.now().strftime('%c')] - # Add messages to queue - for message in messages: - # If there are new lines in a message, split it up to multiple lines - message = message.split("\n") - for submessage in message: - if '' != submessage.strip(): - self.messages.append(submessage.strip()) - - _thread.start_new_thread(self.display_messages, ()) - - def display_messages(self): - if self.animating: - return + def clear(self): + pass - self.animating = True + def write_image(self,imagefile): + pass - max_chars = self.get_max_chars() - max_lines = self.get_max_lines() + def get_max_chars(self): + return int(math.floor(float(self.resolution[0]) / float(self.font_size))) - line_counter = 0 - animate_lines = [] + def get_max_lines(self): + return int(math.floor(float(self.resolution[1]) / float(self.font_size))) - starttime = time.time() - empty_lines = [] - if max_lines > 0 and len(self.messages) > 0: - empty_lines = [''] * int((max_lines - (len(self.messages) % max_lines)) - (0 if not self.get_title() else len(self.messages) / max_lines)) + def get_resolution(self): + return 'x'.join(self.resolution) - for message in self.messages + empty_lines: - self.write_line((line_counter % max_lines)+1,message) - if len(message) > max_chars: - animate_lines.append({'linenr' : (line_counter % max_lines)+1,'message' : message}) + def format_message(self,text): + lines = [] + try: + text = text.decode('utf-8') + except Exception as ex: + pass - line_counter += 1 + for line in text.split("\n"): + if '' == line.strip(): + continue - if line_counter > 0 and line_counter % max_lines == 0: - if len(animate_lines) > 0: - self.animate_lines(animate_lines) + for wrapline in textwrap.wrap(line.strip(),self.get_max_chars()): + if '' == wrapline.strip(): + continue - timeout = float(terrariumScreen.__MAX_SHOW_LINE_TIMEOUT) - (time.time() - starttime) - if timeout >= 0.0: - sleep(timeout) + lines.append(wrapline.strip()) - if self.get_title(): - line_counter += 1 + return lines - animate_lines = [] - starttime = time.time() + def message(self,text): + text_lines = [] + if self.get_title(): + # Set 'now' timestamp as title + text_lines = [datetime.datetime.now().strftime('%c')] - if len(animate_lines) > 0: - self.animate_lines(animate_lines) + text_lines += self.format_message(text) + _thread.start_new_thread(self.display_message, (text_lines,)) - self.animating = False +class terrariumLCD(terrariumScreen): + + def set_address(self,address): + super(terrariumLCD,self).set_address(address) + self.device = lcd(int('0x' + str(self.address),16),int(self.bus)) + + def display_message(self,text_lines): + if self.animating: + return - def animate_lines(self,lines): - max_chars = self.get_max_chars() + self.animating = True - for line in lines: - for counter in range(1,len(line['message'])-max_chars): - self.write_line(line['linenr'],line['message'][counter:max_chars+counter]) - sleep(terrariumScreen.__MAX_SHOW_CHAR_TIMEOUT) + if self.get_title(): + title = text_lines.pop(0).ljust(self.resolution[0]) - for counter in range(len(line['message'])-max_chars,0,-1): - self.write_line(line['linenr'],line['message'][counter:max_chars+counter]) - sleep(terrariumScreen.__MAX_SHOW_CHAR_TIMEOUT) + if len(text_lines) < self.get_max_lines(): + text_lines += [''] * (self.get_max_lines() - (1 if self.get_title() else 0) - len(text_lines)) - self.write_line(line['linenr'],line['message'][:max_chars]) + while len(text_lines) >= self.get_max_lines()- (1 if self.get_title() else 0): + if self.get_title(): + self.device.lcd_display_string(title,1) + + linenr = 0 + while linenr < len(text_lines) and linenr < self.get_max_lines()- (1 if self.get_title() else 0): + self.device.lcd_display_string(text_lines[linenr].ljust(self.resolution[0]),linenr + (2 if self.get_title() else 1)) + linenr += 1 + + text_lines.pop(0) + sleep(0.5) + + self.animating = False + +class terrariumLCD16x2(terrariumLCD): + TYPE = 'LCD16x2' -class terrariumLCD(terrariumScreen): def set_address(self,address): - super(terrariumLCD,self).set_address(address) - self.__screen = lcd(int('0x' + str(self.address),16),int(self.bus)) + super(terrariumLCD16x2,self).set_address(address) + self.resolution = [16,2] - def write_line(self,linenr,text): - text = text[:int(self.resolution[0])].ljust(int(self.resolution[0])) - self.__screen.lcd_display_string(text,linenr) +class terrariumLCD20x4(terrariumLCD): + TYPE = 'LCD20x4' + + def set_address(self,address): + super(terrariumLCD20x4,self).set_address(address) + self.resolution = [20,4] class terrariumLCDSerial(terrariumScreen): + def set_address(self,address): super(terrariumLCDSerial,self).set_address(address) if self.bus == 1: self.bus = 9600 - self.__screen = serial.Serial(self.address, int(self.bus)) + self.device = serial.Serial(self.address, int(self.bus)) def clear(self): - self.__screen.write(str.encode('00clr')) + self.device.write(str.encode('00clr')) sleep(1) - def write_line(self,linenr,text): - text = text[:int(self.resolution[0])].ljust(int(self.resolution[0])) - data = str.encode('0' + str(linenr-1) + str(text)) - self.__screen.write(data) - # Always sleep 1 sec due to slow serial: https://www.instructables.com/id/Raspberry-Pi-Arduino-LCD-Screen/ - sleep(1) + def display_message(self,text_lines): + if self.animating: + return + + self.animating = True + + if self.get_title(): + title = text_lines.pop(0).ljust(self.resolution[0]) + + if len(text_lines) < self.get_max_lines(): + text_lines += [''] * (self.get_max_lines() - (1 if self.get_title() else 0) - len(text_lines)) + + while len(text_lines) >= self.get_max_lines()- (1 if self.get_title() else 0): + if self.get_title(): + self.device.write(str.encode('00' + str(title))) + sleep(1) + + linenr = 0 + while linenr < len(text_lines) and linenr < self.get_max_lines()- (1 if self.get_title() else 0): + self.device.write(str.encode('0' + str(linenr + (1 if self.get_title() else 0)) + str(text_lines[linenr].ljust(self.resolution[0])))) + sleep(1) + linenr += 1 + + text_lines.pop(0) + sleep(0.5) + + self.animating = False + +class terrariumLCDSerial16x2(terrariumLCDSerial): + TYPE = 'LCDSerial16x2' + + def set_address(self,address): + super(terrariumLCDSerial16x2,self).set_address(address) + self.resolution = [16,2] + +class terrariumLCDSerial20x4(terrariumLCDSerial): + TYPE = 'LCDSerial20x4' + + def set_address(self,address): + super(terrariumLCDSerial20x4,self).set_address(address) + self.resolution = [20,4] class terrariumOLED(terrariumScreen): def set_address(self,address): super(terrariumOLED,self).set_address(address) - self.__screen = Adafruit_SSD1306.SSD1306_128_64(rst=None, i2c_address=int('0x' + str(self.address),16), i2c_bus=int(self.bus)) - self.init() def loading(self): self.write_image('static/images/profile_image.jpg') def get_max_chars(self): - return int(float(self.resolution[0]) / (self.font_size/2.0)) + return int(math.floor(float(self.resolution[0]) / (self.font_size/2.0))) def init(self): self.font_size = 10 - self.__screen.begin() - self.__screen.clear() - self.__screen.display() - - self.__canvas = Image.new('1', (int(self.resolution[0]), int(self.resolution[1]))) - draw = ImageDraw.Draw(self.__canvas) - - # Draw a black filled box to clear the image. - draw.rectangle((0,0,int(self.resolution[0])-1,int(self.resolution[1])-1), outline=1, fill=0) - self.__screen.image(self.__canvas) - # Load font - self.__font = ImageFont.truetype('fonts/DejaVuSans.ttf', self.font_size) - - def write_line(self,linenr,text): - draw = ImageDraw.Draw(self.__canvas) - # Clean line - draw.rectangle((1,((linenr-1) * self.font_size)+1,int(self.resolution[0])-2, (((linenr-1) * self.font_size) + self.font_size) ), outline=0, fill=0) - # Write new line - if text != '': - draw.text((1, (linenr-1) * self.font_size), text, font=self.__font, fill=255) - - self.__screen.image(self.__canvas) - self.__screen.display() + self.font = ImageFont.truetype('fonts/DejaVuSans.ttf', self.font_size) + self.resolution = [self.device.width,self.device.height] + self.device.clear() + self.device.show() + + def display_message(self,text_lines): + if self.animating: + return + + self.animating = True + + if self.get_title(): + title = text_lines.pop(0) + + while len(text_lines) > self.get_max_lines() - (1 if self.get_title() else 0): + with canvas(self.device) as draw: + draw.rectangle(self.device.bounding_box, outline='white', fill='black') + linenr = 0 + + if self.get_title(): + draw.rectangle((0,0,self.resolution[0],self.font_size), fill='white') + draw.text((1, linenr * self.font_size), title, font=self.font, fill='black') + linenr += 1 + + while linenr < len(text_lines) and linenr < self.get_max_lines(): + draw.text((1, linenr * self.font_size), text_lines[linenr], font=self.font, fill='white') + linenr += 1 + + text_lines.pop(0) + sleep(1) + + self.animating = False def write_image(self,imagefile): image = Image.open(imagefile) - scale = max(float(self.resolution[0]) / float(image.size[0]),float(self.resolution[1]) / float(image.size[1])) image = image.resize((int(scale * float(image.size[0])),int(scale * float(image.size[1]))),Image.ANTIALIAS) @@ -425,9 +449,71 @@ def write_image(self,imagefile): top_y = int((image.size[1] - int(self.resolution[1])) / 2) image = image.crop((top_x,top_y,top_x + int(self.resolution[0]),top_y + int(self.resolution[1]))) - image = image.convert('1') - self.__screen.image(image) - self.__screen.display() + self.device.display(image.convert(self.device.mode)) + +class terrariumOLEDSSD1306(terrariumOLED): + TYPE = 'SSD1306' + + def set_address(self,address): + super(terrariumOLEDSSD1306,self).set_address(address) + self.device = ssd1306(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSSD1309(terrariumOLED): + TYPE = 'SSD1309' + + def set_address(self,address): + super(terrariumOLEDSSD1309,self).set_address(address) + self.device = ssd1309(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSSD1322(terrariumOLED): + TYPE = 'SSD1322' + + def set_address(self,address): + super(terrariumOLEDSSD1322,self).set_address(address) + self.device = ssd1322(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSSD1325(terrariumOLED): + TYPE = 'SSD1325' + + def set_address(self,address): + super(terrariumOLEDSSD1325,self).set_address(address) + self.device = ssd1325(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSSD1327(terrariumOLED): + TYPE = 'SSD1327' + + def set_address(self,address): + super(terrariumOLEDSSD1327,self).set_address(address) + self.device = ssd1327(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSSD1331(terrariumOLED): + TYPE = 'SSD1331' + + def set_address(self,address): + super(terrariumOLEDSSD1331,self).set_address(address) + self.device = ssd1331(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSSD1351(terrariumOLED): + TYPE = 'SSD1351' + + def set_address(self,address): + super(terrariumOLEDSSD1351,self).set_address(address) + self.device = ssd1351(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() + +class terrariumOLEDSH1106(terrariumOLED): + TYPE = 'SH1106' + + def set_address(self,address): + super(terrariumOLEDSH1106,self).set_address(address) + self.device = sh1106(i2c(port=int(self.bus), address=int('0x' + str(self.address),16))) + self.init() class terrariumDisplaySourceException(Exception): '''The entered display source is not known or invalid''' @@ -435,13 +521,30 @@ class terrariumDisplaySourceException(Exception): # Factory class class terrariumDisplay(object): - def __new__(self,id,address,name,resolution = '16x2',title = False): - if resolution in ['16x2','20x4']: - if address.startswith('/dev/'): - return terrariumLCDSerial(id,address,name,resolution,title) - else: - return terrariumLCD(id,address,name,resolution,title) - elif resolution in ['128x64']: - return terrariumOLED(id,address,name,resolution,title) + DISPLAYS = {terrariumLCD16x2, + terrariumLCD20x4, + terrariumLCDSerial16x2, + terrariumLCDSerial20x4, + terrariumOLEDSSD1306, + terrariumOLEDSSD1309, + terrariumOLEDSSD1322, + terrariumOLEDSSD1325, + terrariumOLEDSSD1327, + terrariumOLEDSSD1331, + terrariumOLEDSSD1351, + terrariumOLEDSH1106 } + + def __new__(self, display_id, hardware_type, address, name = '', title = False): + for display in terrariumDisplay.DISPLAYS: + if hardware_type == display.TYPE: + return display(display_id, address, name, title) + + raise terrariumDisplaySourceException('Display of type {} is unknown. We cannot controll this hardware.'.format(hardware_type)) + + @staticmethod + def valid_hardware_types(): + data = {} + for display in terrariumDisplay.DISPLAYS: + data[display.TYPE] = display.TYPE - raise terrariumDisplaySourceException() + return data diff --git a/terrariumEngine.py b/terrariumEngine.py index 016afa64c..062209bd1 100644 --- a/terrariumEngine.py +++ b/terrariumEngine.py @@ -521,7 +521,7 @@ def __engine_loop(self): alarm_icon = '!' if average_data[env_part]['alarm'] else '' display_message.append('%s%s %.2f%s%s' % (alarm_icon,_(env_part.replace('average_','').title()), average_data[env_part]['current'],average_data[env_part]['indicator'],alarm_icon)) - self.notification.send_display(display_message) + self.notification.send_display("\n".join(display_message)) duration = (time.time() - starttime) + time_short if duration < terrariumEngine.LOOP_TIMEOUT: diff --git a/terrariumNotification.py b/terrariumNotification.py index c835ae3ab..cb6fcd2ad 100644 --- a/terrariumNotification.py +++ b/terrariumNotification.py @@ -326,8 +326,22 @@ def __load_config(self): proxy) if self.__data.has_section('display'): + + try: + self.__data.get('display','hardwaretype') + except Exception as ex: + address = self.__data.get('display','address') + resolution = self.__data.get('display','resolution') + + if '/dev/' in address: + self.__data.set('display', 'hardwaretype', 'LCDSerial16x2') + elif '128x64' in resolution: + self.__data.set('display', 'hardwaretype', 'SSD1306') + else: + self.__data.set('display', 'hardwaretype', 'LCD16x2') + self.set_display(self.__data.get('display','address'), - self.__data.get('display','resolution'), + self.__data.get('display','hardwaretype'), self.__data.get('display','title')) if self.__data.has_section('webhook'): @@ -580,20 +594,21 @@ def send_telegram(self,subject,message,files = []): else: self.telegram.send_image(subject.decode('utf-8'),files) - def set_display(self,address,resolution,title): + def set_display(self,address,hardwaretype,title): self.display = None if address is not None and '' != address: try: - self.display = terrariumDisplay(None,address,'notification',resolution,title) + self.display = terrariumDisplay(None,hardwaretype,address,'notification',title) except terrariumDisplaySourceException as ex: + print(ex) self.display = None if self.__profile_image is not None: self.display.write_image(self.__profile_image) - def send_display(self,messages): + def send_display(self,message): if self.display is not None: - self.display.message(messages) + self.display.message(message) def set_webhook(self,address): self.webhook = {'address' : address} @@ -701,8 +716,9 @@ def set_config(self,data): 'proxy' : data['telegram_proxy']}) self.__update_config('display',{'address' : data['display_address'], - 'resolution' : data['display_resolution'], - 'title' : data['display_title']}) + 'hardwaretype' : data['display_hardwaretype'], + 'title' : data['display_title']}, + ['resolution']) self.__update_config('webhook',{'address' : data['webhook_address']}) diff --git a/terrariumTranslations.py b/terrariumTranslations.py index 4f3f91e58..78810959e 100644 --- a/terrariumTranslations.py +++ b/terrariumTranslations.py @@ -122,8 +122,8 @@ def __load(self): self.translations['notification_email_email_username'] = _('Holds the username for authentication with the mailserver if needed.') self.translations['notification_email_email_password'] = _('Holds the password for authentication with the mailserver if needed.') + self.translations['notification_display_hardwaretype'] = _('Holds the display chip that is used.') self.translations['notification_display_address'] = _('Holds the I2C address of the LCD screen. Use the value found with i2cdetect. Add ,[NR] to change the I2C bus.') - self.translations['notification_display_resolution'] = _('Holds the LCD screen resolution.') self.translations['notification_display_title'] = _('Reserve first LCD line for static title.') self.translations['notification_twitter_consumer_key'] = _('Holds your Twitter consumer key. More information %shere%s') % ('','') diff --git a/views/notifications.tpl b/views/notifications.tpl index 80c8c7590..8a7bb40a3 100644 --- a/views/notifications.tpl +++ b/views/notifications.tpl @@ -71,19 +71,16 @@
- - -
-
- -
-
+
+ + +
@@ -340,6 +337,10 @@ switch (part) { case 'email': case 'display': + $.each(partdata.supported,function(key,value){ + $('select[name="display_hardwaretype"]').append($('