diff --git a/.buildbot/openwrt/build.sh b/.buildbot/openwrt/build.sh index 3ff677f..99fce42 100755 --- a/.buildbot/openwrt/build.sh +++ b/.buildbot/openwrt/build.sh @@ -47,6 +47,7 @@ make package/ansible-core/compile make package/asterisk-chan-quectel/compile make package/collectd/compile make package/python3-packages/compile +make package/waveshare-demo/compile sdkdir=$(pwd) cd ${pwd} @@ -153,7 +154,7 @@ make image PROFILE=${PROFILE} EXTRA_IMAGE_NAME="waveshare" \ ${PACKAGES} cryptsetup kmod-ata-ahci smartmontools hdparm fdisk parted \ kmod-hwmon-drivetemp btrfs-progs kmod-fs-btrfs kmod-nvme nvme-cli \ docker dockerd docker-compose block-mount \ - python3-packages python3-spidev" \ + python3-packages python3-spidev python3-waveshare-demo" \ DISABLED_SERVICES="dropbear" FILES="files" || exit 1 diff --git a/feed/waveshare-demo/Makefile b/feed/waveshare-demo/Makefile new file mode 100644 index 0000000..741103b --- /dev/null +++ b/feed/waveshare-demo/Makefile @@ -0,0 +1,32 @@ +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=waveshare-demo +PKG_VERSION:=0.0.2 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Lee Miller +PKG_LICENSE:=BSD + +include $(INCLUDE_DIR)/package.mk +include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk + +define Package/python3-$(PKG_NAME) + SECTION:=lang + CATEGORY:=Languages + SUBMENU:=Python + TITLE:=CM4-NAS-Double-Deck Demo + URL:=https://www.waveshare.com/wiki/CM4-NAS-Double-Deck + DEPENDS:=+python3 +python3-setuptools +python3-numpy +python3-pillow \ + +python3-spidev +lsblk +procps-ng +endef + +define Package/python3-$(PKG_NAME)/description + CM4-NAS-Double-Deck Demo +endef + +$(eval $(call Py3Package,python3-$(PKG_NAME))) +$(eval $(call BuildPackage,python3-$(PKG_NAME))) diff --git a/feed/waveshare-demo/src/Font/Font02.ttf b/feed/waveshare-demo/src/Font/Font02.ttf new file mode 100644 index 0000000..f8f46ee Binary files /dev/null and b/feed/waveshare-demo/src/Font/Font02.ttf differ diff --git a/feed/waveshare-demo/src/pic/BL.jpg b/feed/waveshare-demo/src/pic/BL.jpg new file mode 100644 index 0000000..659e943 Binary files /dev/null and b/feed/waveshare-demo/src/pic/BL.jpg differ diff --git a/feed/waveshare-demo/src/pic/Disk.jpg b/feed/waveshare-demo/src/pic/Disk.jpg new file mode 100644 index 0000000..2e7b5a1 Binary files /dev/null and b/feed/waveshare-demo/src/pic/Disk.jpg differ diff --git a/feed/waveshare-demo/src/setup.py b/feed/waveshare-demo/src/setup.py new file mode 100644 index 0000000..8397ca9 --- /dev/null +++ b/feed/waveshare-demo/src/setup.py @@ -0,0 +1,15 @@ + +from setuptools import setup + + +setup( + name='waveshare', + version='0.0.2', + description='CM4-NAS-Double-Deck Demo packaged', + url='https://www.waveshare.com/wiki/CM4-NAS-Double-Deck', + install_requires=['spidev', 'RPi.GPIO', 'numpy'], + packages=['waveshare', 'waveshare.lib'], + package_data={ + 'waveshare': ['Font/*.ttf', 'pic/*.jpg']}, + entry_points={'console_scripts': ['waveshare-demo = waveshare.main']} +) diff --git a/feed/waveshare-demo/src/waveshare/__init__.py b/feed/waveshare-demo/src/waveshare/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/feed/waveshare-demo/src/waveshare/image.py b/feed/waveshare-demo/src/waveshare/image.py new file mode 100644 index 0000000..887ccf8 --- /dev/null +++ b/feed/waveshare-demo/src/waveshare/image.py @@ -0,0 +1,572 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +import time +import logging + +import math +import re +import threading +from PIL import Image, ImageDraw, ImageFont + +import RPi.GPIO as GPIO + +from .lib import LCD_2inch +from .lib import Gain_Param + + +logging.basicConfig(level=logging.DEBUG) + +app_dir = os.path.dirname(os.path.realpath(__file__)) + + +class image(): + flgh = True + + def __init__(self): + # display with hardware SPI: + ''' Warning!!!Don't creation of multiple displayer objects!!! ''' + + self.gain = Gain_Param.Gain_Param() + GPIO.setmode(GPIO.BCM) + GPIO.setup(20, GPIO.IN) + GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP) + t1 = threading.Thread(target=self.gain.Hard_data, name="thread1") + t2 = threading.Thread(target=self.key, name="thread2") + t1.daemon = True + t2.daemon = True + t1.start() + t2.start() + + self.disp = LCD_2inch.LCD_2inch() + + # Initialize library. + self.disp.Init() + # Clear display. + self.disp.clear() + + # Create blank image for drawing. + self.image1 = Image.new( + "RGB", (self.disp.height, self.disp.width), "WHITE") + self.draw = ImageDraw.Draw(self.image1) + + def key(self): + count = 0 + while True: + if GPIO.input(20) == 0: + count = count + 1 + else: + if count > 5: + self.flgh = not self.flgh + count = 0 + + def HMI1(self): + try: + self.image = Image.open(os.path.join(app_dir, "pic", "BL.jpg")) + + self.draw = ImageDraw.Draw(self.image) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 28) + self.draw.text((90, 2), 'Device Status', fill=0xf7ba47, font=Font1) + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text((267, 141), 'TEMP', fill=0xf7ba47, font=Font1) + self.draw.text((190, 141), 'RAM', fill=0xf7ba47, font=Font1) + self.draw.text((267, 141), 'TEMP', fill=0xf7ba47, font=Font1) + self.draw.text((30, 141), 'CPU', fill=0xf7ba47, font=Font1) + self.draw.text((107, 141), 'Disk', fill=0xf7ba47, font=Font1) + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 10) + self.draw.text( + (205, 170), 'R X', fill=0xffffff, font=Font1, stroke_width=1) + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 10) + self.draw.text( + (270, 170), 'T X', fill=0xffffff, font=Font1, stroke_width=1) + + # TIME 时间 + time_t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text((5, 50), time_t, fill=0xf7ba47, font=Font1) + + # IP + ip = self.gain.GET_IP() + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text((170, 50), 'IP : ' + ip, fill=0xf7ba47, font=Font1) + + # CPU usage CPU使用率 + self.CPU_usage = os.popen( + 'top -bi -n 2 -d 0.02' + ).read().split('\n\n\n')[0].split('\n')[2] + self.CPU_usage = re.sub('[a-zA-z%(): ]', '', self.CPU_usage) + self.CPU_usage = self.CPU_usage.split(',') + + self.CPU_usagex = 100 - eval(self.CPU_usage[3]) + + if self.CPU_usagex >= 100: + self.draw.text( + (27, 100), str(math.floor(self.CPU_usagex)) + '%', + fill=0xf1b400, font=Font1) + elif self.CPU_usagex >= 10: + self.draw.text( + (30, 100), str(math.floor(self.CPU_usagex)) + '%', + fill=0xf1b400, font=Font1) + else: + self.draw.text( + (34, 100), str(math.floor(self.CPU_usagex)) + '%', + fill=0xf1b400, font=Font1) + + self.draw.arc((10, 80, 70, 142), 0, 360, fill=0xffffff, width=8) + self.draw.arc( + (10, 80, 70, 142), -90, -90 + self.CPU_usagex * 360 / 100, + fill=0x60ad4c, width=8) + + # System disk usage 系统磁盘使用率 + x = os.popen('df -h /') + i2 = 0 + while 1: + i2 = i2 + 1 + line = x.readline() + if i2 == 2: + # Memory usage (%) 使用内存(百分值) + self.Capacity_usage = line.split()[4] + self.Hard_capacity = int( + re.sub('[%]', '', self.Capacity_usage)) + break + if self.Hard_capacity >= 100: + self.draw.text( + (107, 100), str(math.floor(self.Hard_capacity)) + '%', + fill=0xf1b400, font=Font1) + elif self.Hard_capacity >= 10: + self.draw.text( + (111, 100), str(math.floor(self.Hard_capacity)) + '%', + fill=0xf1b400, font=Font1) + else: + self.draw.text( + (114, 100), str(math.floor(self.Hard_capacity)) + '%', + fill=0xf1b400, font=Font1) + + self.draw.arc((90, 80, 150, 142), 0, 360, fill=0xffffff, width=8) + self.draw.arc( + (90, 80, 150, 142), -90, -90 + self.Hard_capacity * 360 / 100, + fill=0x7f35e9, width=8) + + # TEMP 温度 + self.temp_t = self.gain.GET_Temp() + if self.temp_t < 45: + self.disp._pwm1.ChangeDutyCycle(50) + elif self.temp_t < 50: + self.disp._pwm1.ChangeDutyCycle(70) + elif self.temp_t < 55: + self.disp._pwm1.ChangeDutyCycle(80) + else: + self.disp._pwm1.ChangeDutyCycle(100) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 18) + self.draw.text( + (268, 100), str(math.floor(self.temp_t)) + '℃', + fill=0x0088ff, font=Font1) + + self.draw.arc((253, 80, 313, 142), 0, 360, fill=0xffffff, width=8) + self.draw.arc( + (253, 80, 313, 142), -90, -90 + self.temp_t * 360 / 100, + fill=0x0088ff, width=8) + + # speed 网速 + + TX = self.gain.TX_speed() * 1024 + + if TX < 1024: # B + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 18) + self.draw.text( + (250, 190), str(math.floor(TX)) + 'B/s', + fill=0x00ff00, font=Font1) + + elif TX < 1024 * 1024: # K + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 17) + self.draw.text( + (249, 190), str(math.floor(TX/1024)) + 'KB/s', + fill=0x00ffff, font=Font1) + + else: # M + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 18) + self.draw.text( + (250, 190), str(math.floor(TX/1024/1024)) + 'M/s', + fill=0x008fff, font=Font1) + + TX = self.gain.RX_speed() * 1024 + + if TX < 1024: # B + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 18) + self.draw.text( + (183, 190), str(math.floor(TX)) + 'B/s', + fill=0x00ff00, font=Font1) + + elif TX < 1024 * 1024: # K + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 17) + self.draw.text( + (180, 190), str(math.floor(TX/1024)) + 'KB/s', + fill=0x008fff, font=Font1) + + else: # M + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 18) + self.draw.text( + (181, 190), str(math.floor(TX/1024/1024)) + 'M/s', + fill=0x008fff, font=Font1) + + # memory_percentage 内存百分比 + tot_m, used_m, free_m = map( + int, os.popen('free -t -m').readlines()[-1].split()[1:]) + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 18) + memory_percentage = 100 - free_m / tot_m * 100 + + if memory_percentage >= 100: + self.draw.text( + (186, 100), str(math.floor(memory_percentage)) + '%', + fill=0xf1b400, font=Font1) + elif memory_percentage >= 10: + self.draw.text( + (189, 100), str(math.floor(memory_percentage)) + '%', + fill=0xf1b400, font=Font1) + else: + self.draw.text( + (195, 100), str(math.floor(memory_percentage)) + '%', + fill=0xf1b400, font=Font1) + self.draw.arc((173, 80, 233, 142), 0, 360, fill=0xffffff, width=8) + self.draw.arc( + (173, 80, 233, 142), -90, -90 + memory_percentage * 360 / 100, + fill=0xf1b400, width=8) + + # Disk 使用情况 + if self.gain.Get_back[0] == 0: + self.draw.rectangle((40, 177, 142, 190)) + self.draw.rectangle((41, 178, 141, 189), fill=0x000000) + else: + self.draw.rectangle((40, 177, 142, 190)) + self.draw.rectangle( + (41, 178, 41 + self.gain.Get_back[2], 189), fill=0x7f35e9) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 13) + self.draw.text( + (80, 176), str(math.floor(self.gain.Get_back[2])) + '%', + fill=0xf1b400, font=Font1) + + if self.gain.Get_back[1] == 0: + self.draw.rectangle((40, 197, 142, 210)) + self.draw.rectangle((41, 198, 141, 209), fill=0x000000) + else: + self.draw.rectangle((40, 197, 142, 210)) + self.draw.rectangle( + (41, 198, 41 + self.gain.Get_back[3], 209), fill=0x7f35e9) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 13) + self.draw.text( + (80, 196), str(math.floor(self.gain.Get_back[3])) + '%', + fill=0xf1b400, font=Font1) + if self.gain.Get_back[4] == 1: + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text((40, 161), 'RAID', fill=0xf7ba47, font=Font1) + + if ( + (self.gain.Get_back[0] == 0 and self.gain.Get_back[1] == 0) + or (self.gain.Get_back[0] != 0 and self.gain.Get_back[1] == 0) + or (self.gain.Get_back[0] == 0 and self.gain.Get_back[1] != 0) + ): + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + if self.gain.flag > 0: + self.draw.text( + (30, 210), 'Detected but not installed', + fill=0xf7ba47, font=Font1) + else: + self.draw.text( + (50, 210), 'Unpartitioned/NC', + fill=0xf7ba47, font=Font1) + + self.image = self.image.rotate(180) + self.disp.ShowImage(self.image) + + # time.sleep(0.5) + except IOError as e: + logging.info(e) + except KeyboardInterrupt: + self.disp.module_exit() + logging.info("quit:") + exit() + + def HMI2(self): + try: + self.image = Image.open(os.path.join(app_dir, "pic", 'Disk.jpg')) + + self.draw = ImageDraw.Draw(self.image) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 20) + self.draw.text((60, 55), 'CPU Used', fill=0xC1C0BE, font=Font1) + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 13) + self.draw.text((45, 140), 'Used', fill=0xC1C0BE, font=Font1) + self.draw.text((45, 163), 'Free', fill=0xC1C0BE, font=Font1) + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 14) + self.draw.text((185, 93), 'Disk0:', fill=0xC1C0BE, font=Font1) + self.draw.text((185, 114), 'Disk1:', fill=0xC1C0BE, font=Font1) + + self.draw.text((188, 155), 'TX:', fill=0xC1C0BE, font=Font1) + self.draw.text((188, 175), 'RX:', fill=0xC1C0BE, font=Font1) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text((133, 205), 'TEMP:', fill=0x0088ff, font=Font1) + + # TIME 时间 + time_t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text((40, 10), time_t, fill=0xffffff, font=Font1) + + # IP + ip = self.gain.GET_IP() + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 17) + self.draw.text((155, 58), 'IP : ' + ip, fill=0xC1C0BE, font=Font1) + + # CPU usage CPU使用率 + self.CPU_usage = os.popen( + 'top -bi -n 2 -d 0.02' + ).read().split('\n\n\n')[0].split('\n')[2] + self.CPU_usage = re.sub('[a-zA-z%(): ]', '', self.CPU_usage) + self.CPU_usage = self.CPU_usage.split(',') + self.CPU_usagex = 100 - eval(self.CPU_usage[3]) + + if self.CPU_usagex >= 100: + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 10) + self.draw.text( + (80, 107), str(math.floor(self.CPU_usagex)) + '%', + fill=0xf1b400, font=Font1) + elif self.CPU_usagex >= 10: + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 13) + self.draw.text( + (79, 105), str(math.floor(self.CPU_usagex)) + '%', + fill=0xf1b400, font=Font1) + else: + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text( + (81, 104), str(math.floor(self.CPU_usagex)) + '%', + fill=0xf1b400, font=Font1) + + self.draw.arc( + (66, 90, 111, 135), -90, -90 + self.CPU_usagex * 360 / 100, + fill=0x7f35e9, width=3) + + # System disk usage 系统磁盘使用率 + x = os.popen('df -h /') + i2 = 0 + while 1: + i2 = i2 + 1 + line = x.readline() + if i2 == 2: + self.Capacity_Used = line.split()[2] + self.Capacity_Avail = line.split()[3] + if ( + self.Capacity_Used.count('G') + and self.Capacity_Avail.count('G') + ): + self.Used_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Used)) * 1024 + self.Avail_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Avail)) * 1024 + elif ( + self.Capacity_Used.count('G') + and self.Capacity_Avail.count('M') + ): + self.Used_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Used)) * 1024 + self.Avail_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Avail)) + elif ( + self.Capacity_Used.count('M') + and self.Capacity_Avail.count('G') + ): + self.Used_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Used)) + self.Avail_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Avail)) * 1024 + else: + self.Used_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Used)) + self.Avail_capacity = float( + re.sub('[A-Z]', '', self.Capacity_Avail)) + + break + if(self.Used_capacity > 1024 and self.Avail_capacity > 1024): + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 13) + self.draw.text((125, 140), 'G', fill=0xC1C0BE, font=Font1) + self.draw.text((125, 163), 'G', fill=0xC1C0BE, font=Font1) + self.Used_capacity = self.Used_capacity / 1024 + self.Avail_capacity = self.Avail_capacity / 1024 + + self.Disk_always = self.Used_capacity + self.Avail_capacity + if self.Disk_always <= 99: + self.draw.text( + (100, 140), str(round(self.Used_capacity, 2)), + fill=0xC1C0BE, font=Font1) + self.draw.text( + (100, 163), str(round(self.Avail_capacity, 2)), + fill=0xC1C0BE, font=Font1,) + elif self.Disk_always > 99: + self.draw.text( + (85, 140), str(round(self.Used_capacity, 2)), + fill=0xC1C0BE, font=Font1) + self.draw.text( + (85, 163), str(round(self.Avail_capacity, 2)), + fill=0xC1C0BE, font=Font1) + else: + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 13) + self.draw.text((125, 140), 'M', fill=0xC1C0BE, font=Font1) + self.draw.text((125, 163), 'M', fill=0xC1C0BE, font=Font1) + self.Disk_always = self.Used_capacity + self.Avail_capacity + self.draw.text( + (80, 140), str(round(self.Used_capacity, 2)), + fill=0xC1C0BE, font=Font1) + self.draw.text( + (80, 163), str(round(self.Avail_capacity, 2)), + fill=0xC1C0BE, font=Font1) + + self.draw.rectangle(( + 45, 157, 45 + self.Used_capacity / self.Disk_always * 87, 160 + ), fill=0x7f35e9) + self.draw.rectangle(( + 45, 180, 45 + self.Avail_capacity / self.Disk_always * 87, 183 + ), fill=0x7f35e9) + + # TEMP 温度 + temp_t = self.gain.GET_Temp() + if self.temp_t < 45: + self.disp._pwm1.ChangeDutyCycle(50) + elif self.temp_t < 50: + self.disp._pwm1.ChangeDutyCycle(70) + elif self.temp_t < 55: + self.disp._pwm1.ChangeDutyCycle(80) + else: + self.disp._pwm1.ChangeDutyCycle(100) + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + self.draw.text( + (170, 205), str(math.floor(temp_t))+'℃', + fill=0x0088ff, font=Font1) + + # speed 网速 + TX = self.gain.TX_speed() * 1024 + + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 15) + if TX < 1024: # B + self.draw.text( + (210, 154), str(math.floor(TX)) + 'B/s', + fill=0x00ff00, font=Font1) + + elif TX < 1024*1024: # K + self.draw.text( + (210, 154), str(math.floor(TX/1024)) + 'KB/s', + fill=0x00ffff, font=Font1) + + else: # M + self.draw.text( + (210, 154), str(math.floor(TX/1024/1024)) + 'M/s', + fill=0x008fff, font=Font1) + + TX = self.gain.RX_speed() * 1024 + + if TX < 1024: # B + self.draw.text( + (210, 174), str(math.floor(TX)) + 'B/s', + fill=0x00ff00, font=Font1) + + elif TX < 1024*1024: # K + self.draw.text( + (210, 174), str(math.floor(TX/1024)) + 'KB/s', + fill=0x008fff, font=Font1) + + else: # M + self.draw.text( + (210, 174), str(math.floor(TX/1024/1024)) + 'M/s', + fill=0x008fff, font=Font1) + + # Disk 使用情况 + + self.Disk0_Avail = self.gain.Get_back[0] - ( + self.gain.Get_back[0] * self.gain.Get_back[2] // 100) + self.Disk1_Avail = self.gain.Get_back[1] - ( + self.gain.Get_back[1] * self.gain.Get_back[3] // 100) + + self.draw.text( + (240, 93), str(math.floor(self.Disk0_Avail)) + 'G', + fill=0xC1C0BE, font=Font1) + self.draw.text( + (240, 114), str(math.floor(self.Disk1_Avail)) + 'G', + fill=0xC1C0BE, font=Font1) + + if self.gain.Get_back[0] == 0: + self.draw.rectangle((186, 110, 273, 113), fill=0x000000) + else: + self.draw.rectangle( + (186, 110, 186 + self.gain.Get_back[2] * 87 / 100, 113), + fill=0x7f35e9) + + if self.gain.Get_back[1] == 0: + self.draw.rectangle((186, 131, 273, 134), fill=0x000000) + else: + self.draw.rectangle( + (186, 131, 186 + self.gain.Get_back[3] * 87 / 100, 134), + fill=0x7f35e9) + + if self.gain.Get_back[4] == 1: + self.draw.text((160, 78), 'RAID', fill=0xC1C0BE, font=Font1) + + if ( + (self.gain.Get_back[0] == 0 and self.gain.Get_back[1] == 0) + or (self.gain.Get_back[0] != 0 and self.gain.Get_back[1] == 0) + or (self.gain.Get_back[0] == 0 and self.gain.Get_back[1] != 0) + ): + Font1 = ImageFont.truetype( + os.path.join(app_dir, "Font", "Font02.ttf"), 14) + if self.gain.flag > 0: + self.draw.text( + (155, 135), 'Detected but not installed', + fill=0xC1C0BE, font=Font1) + else: + self.draw.text( + (190, 135), 'Unpartitioned/NC', + fill=0xC1C0BE, font=Font1) + + self.image = self.image.rotate(180) + self.disp.ShowImage(self.image) + # time.sleep(0.5) + + except IOError as e: + logging.info(e) + except KeyboardInterrupt: + self.disp.module_exit() + logging.info("quit:") + exit() diff --git a/feed/waveshare-demo/src/waveshare/lib/Gain_Param.py b/feed/waveshare-demo/src/waveshare/lib/Gain_Param.py new file mode 100644 index 0000000..31e35c0 --- /dev/null +++ b/feed/waveshare-demo/src/waveshare/lib/Gain_Param.py @@ -0,0 +1,233 @@ +# -*- coding: utf-8 -*- +import os +import re +import time +import socket + + +class Gain_Param(): + Get_back = [0, 0, 0, 0, 0] # 返回Disk的内存 + flag = 0 # 未挂载还是未分区 + + def GET_IP(self): + # 会存在异常 卡死 谨慎获取 + # There will be exceptions, get stuck, get it carefully + # Threading is better + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect_ex(('8.8.8.8', 80)) + ip = s.getsockname()[0] + s.close() + return ip + + def GET_Temp(self): + with open('/sys/class/thermal/thermal_zone0/temp', 'rt') as f: + temp = int(f.read()) / 1000.0 + # print(temp) + return temp + + def net_speed(self, interface, is_download): + # Get the corresponding value 获取对应值 + which_num = 0 if is_download else 8 + + # Read the file 读取文件 + with open('/proc/net/dev') as f: + lines = f.readlines() + # Get result value 获取结果值 + for line in lines: + if line.rstrip().split(':')[0].strip() == interface: + return line.rstrip().split(':')[1].split()[which_num] + + def RX_speed(self): + interface = 'eth0' + is_upload = True # False + get_time = 0.1 + # Computation part 计算部分 + begin = int(self.net_speed(interface, is_upload)) + time.sleep(get_time) + end = int(self.net_speed(interface, is_upload)) + return ((end - begin) / get_time / 1024) + + def TX_speed(self): + interface = 'eth0' + is_upload = False + get_time = 0.1 + # Computation part 计算部分 + begin = int(self.net_speed(interface, is_upload)) + time.sleep(get_time) + end = int(self.net_speed(interface, is_upload)) + + return ((end - begin) / get_time / 1024) + + def Hard_data(self): + while True: + Hard_capacity1 = os.popen('lsblk -f ').read().split('\n\n\n')[0] + Disk_number = sum( + 1 for i in re.finditer(r'^[a-z]', Hard_capacity1, re.MULTILINE) + ) + Hard_segmentation = Hard_capacity1.split('\n\n\n')[0].split('\n') + + k = 0 # Counting migration 计数偏移 + j = 0 # 连接盘的数量 + + Disk0_capacity = 0 # total capacity 总容量 + Disk0_usege = 0 # have been used 已使用 + Disk1_capacity = 0 + Disk1_usege = 0 + + for i in range(0, Disk_number): + if i == 0: + a = Hard_segmentation[k+1].strip().split() + if len(a) != 1: + if a[1].count('raid') == 1: + self.Get_back[4] = 1 # 检测是否组RAID '1'表示组了 + else: + self.Get_back[4] = 0 + if(a[0].count('mmcblk') == 1): + continue + name0 = a[0] + + else: + a = Hard_segmentation[k+1].strip().split() + if a[0].count('mmcblk') == 1: + continue + + if len(a) != 1: + if a[1].count('raid') == 1: + self.Get_back[4] = 1 # 检测是否组RAID '1'表示组了 + else: + self.Get_back[4] = 0 + flgh = 0 + + j = j + 1 + + if len(a) == 1: + disk_partition_Number = Hard_capacity1.count('─'+a[0]) + self.Get_back[4] = 0 + else: + if a[1].count('raid') == 0: + self.Get_back[4] = 0 + disk_partition_Number = Hard_capacity1.count('─'+a[0]) + else: + disk_partition_Number = 1 + self.Get_back[4] = 1 + + if(disk_partition_Number == 0): + disk_partition_Number = 1 + flgh = 1 + + for i1 in range(0, disk_partition_Number): + if (disk_partition_Number > 0 and flgh == 0): + Partition_data_split = ' '.join( + Hard_segmentation[i1+2+k].split()).split(' ') + else: + Partition_data_split = ' '.join( + Hard_segmentation[i1+1+k].split()).split(' ') + if ( + len(Partition_data_split) <= 5 + and len(Partition_data_split) > 0 + ): + # name = re.sub('[├─└]', '', Partition_data_split[0]) + if len(Partition_data_split) == 1: + self.flag = 0 + else: + # print( + # "%s This drive letter is not mounted\n" + # % name) + self.flag = 1 # 检测是否挂载盘 ‘1’表示没有挂载 + # continue + else: + # print("%s The drive letter is properly mounted\n" % ( + # re.sub('[├─└]', '', Partition_data_split[0]))) + if ( + disk_partition_Number > 0 and name0 == a[0] + or self.Get_back[4] == 1 + ): + p = os.popen( + "df -h " + Partition_data_split[len( + Partition_data_split) - 1]) + i2 = 0 + while 1: + i2 = i2 + 1 + line = p.readline() + if i2 == 2: + #: Total cost of the partition 分区总值 + Capacity = line.split()[1] + x = int(re.sub('[A-Za-z]', '', Capacity)) + Disk0_capacity = Disk0_capacity + x + Capacity = "".join(list(filter( + str.isdigit, Capacity))) + # Partition memory usage 分区使用内存 + Capacity_usage = line.split()[2] + if Capacity_usage.count('G'): + x = float(re.sub( + '[A-Z]', '', Capacity_usage)) + Disk0_usege = Disk0_usege + x + break + else: + x = float(re.sub( + '[A-Z]', '', Capacity_usage) + ) / 1024 + Disk0_usege = Disk0_usege + x + break + else: + p = os.popen( + "df -h " + Partition_data_split[len( + Partition_data_split) - 1]) + i2 = 0 + while 1: + i2 = i2 + 1 + line = p.readline() + if i2 == 2: + # Total cost of the partition 分区总值 + Capacity = line.split()[1] + x = int(re.sub('[A-Za-z]', '', Capacity)) + Disk1_capacity = Disk1_capacity + x + + # Partition memory usage 分区使用内存 + Capacity_usage = line.split()[2] + if(Capacity_usage.count('G')): + x = float(re.sub( + '[A-Z]', '', Capacity_usage)) + Disk1_usege = Disk1_usege + x + break + else: + x = float(re.sub( + '[A-Z]', '', Capacity_usage) + ) / 1024 + Disk1_usege = Disk1_usege + x + break + + if(flgh == 0): + k = k + disk_partition_Number + 1 + else: + k = k + disk_partition_Number + + if j == 1 and len(Partition_data_split) > 5: + self.flag = 0 + if self.Get_back[4] == 1: + Disk1_capacity = Disk0_capacity / 2 + Disk0_capacity = Disk1_capacity + Disk1_usege = Disk0_usege / 2 + Disk0_usege = Disk1_usege + + if Disk0_capacity == 0 and Disk1_capacity == 0: + self.Get_back = [ + Disk0_capacity, Disk1_capacity, Disk0_usege, Disk1_usege, + self.Get_back[4]] + elif Disk0_capacity == 0 and Disk1_capacity != 0: + Disk1_usege = round(Disk1_usege / Disk1_capacity * 100, 0) + self.Get_back = [ + Disk0_capacity, Disk1_capacity, Disk0_usege, Disk1_usege, + self.Get_back[4]] + elif Disk0_capacity != 0 and Disk1_capacity == 0: + Disk0_usege = round(Disk0_usege / Disk0_capacity * 100, 0) + self.Get_back = [ + Disk0_capacity, Disk1_capacity, Disk0_usege, Disk1_usege, + self.Get_back[4]] + else: + Disk0_usege = round(Disk0_usege / Disk0_capacity * 100, 0) + Disk1_usege = round(Disk1_usege / Disk1_capacity * 100, 0) + self.Get_back = [ + Disk0_capacity, Disk1_capacity, Disk0_usege, Disk1_usege, + self.Get_back[4]] + time.sleep(1.5) diff --git a/feed/waveshare-demo/src/waveshare/lib/LCD_2inch.py b/feed/waveshare-demo/src/waveshare/lib/LCD_2inch.py new file mode 100644 index 0000000..64da19c --- /dev/null +++ b/feed/waveshare-demo/src/waveshare/lib/LCD_2inch.py @@ -0,0 +1,185 @@ + +import time +from . import lcdconfig + + +class LCD_2inch(lcdconfig.RaspberryPi): + + width = 240 + height = 320 + + def command(self, cmd): + self.digital_write(self.DC_PIN, self.GPIO.LOW) + self.spi_writebyte([cmd]) + + def data(self, val): + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + self.spi_writebyte([val]) + + def reset(self): + """Reset the display""" + self.GPIO.output(self.RST_PIN, self.GPIO.HIGH) + time.sleep(0.01) + self.GPIO.output(self.RST_PIN, self.GPIO.LOW) + time.sleep(0.01) + self.GPIO.output(self.RST_PIN, self.GPIO.HIGH) + time.sleep(0.01) + + def Init(self): + """Initialize dispaly""" + self.module_init() + self.reset() + + self.command(0x36) + self.data(0x00) + + self.command(0x3A) + self.data(0x05) + + self.command(0x21) + + self.command(0x2A) + self.data(0x00) + self.data(0x00) + self.data(0x01) + self.data(0x3F) + + self.command(0x2B) + self.data(0x00) + self.data(0x00) + self.data(0x00) + self.data(0xEF) + + self.command(0xB2) + self.data(0x0C) + self.data(0x0C) + self.data(0x00) + self.data(0x33) + self.data(0x33) + + self.command(0xB7) + self.data(0x35) + + self.command(0xBB) + self.data(0x1F) + + self.command(0xC0) + self.data(0x2C) + + self.command(0xC2) + self.data(0x01) + + self.command(0xC3) + self.data(0x12) + + self.command(0xC4) + self.data(0x20) + + self.command(0xC6) + self.data(0x0F) + + self.command(0xD0) + self.data(0xA4) + self.data(0xA1) + + self.command(0xE0) + self.data(0xD0) + self.data(0x08) + self.data(0x11) + self.data(0x08) + self.data(0x0C) + self.data(0x15) + self.data(0x39) + self.data(0x33) + self.data(0x50) + self.data(0x36) + self.data(0x13) + self.data(0x14) + self.data(0x29) + self.data(0x2D) + + self.command(0xE1) + self.data(0xD0) + self.data(0x08) + self.data(0x10) + self.data(0x08) + self.data(0x06) + self.data(0x06) + self.data(0x39) + self.data(0x44) + self.data(0x51) + self.data(0x0B) + self.data(0x16) + self.data(0x14) + self.data(0x2F) + self.data(0x31) + self.command(0x21) + + self.command(0x11) + + self.command(0x29) + + def SetWindows(self, Xstart, Ystart, Xend, Yend): + self.command(0x2A) + #: set the X coordinates + self.data(Xstart >> 8) + #: Set the horizontal starting point to the high octet + self.data(Xstart & 0xff) + #: Set the horizontal starting point to the low octet + self.data(Xend >> 8) + #: Set the horizontal end to the high octet + self.data((Xend - 1) & 0xff) + #: Set the horizontal end to the low octet + + self.command(0x2B) + #: set the Y coordinates + self.data(Ystart >> 8) + self.data((Ystart & 0xff)) + self.data(Yend >> 8) + self.data((Yend - 1) & 0xff) + + self.command(0x2C) + + def ShowImage(self, Image, Xstart=0, Ystart=0): + """Set buffer to value of Python Imaging Library image.""" + """Write display buffer to physical display""" + imwidth, imheight = Image.size + if imwidth == self.height and imheight == self.width: + img = self.np.asarray(Image) + pix = self.np.zeros( + (self.width, self.height, 2), dtype=self.np.uint8) + # RGB888 >> RGB565 + pix[...,[0]] = self.np.add(self.np.bitwise_and(img[...,[0]],0xF8),self.np.right_shift(img[...,[1]],5)) + pix[...,[1]] = self.np.add(self.np.bitwise_and(self.np.left_shift(img[...,[1]],3),0xE0), self.np.right_shift(img[...,[2]],3)) + pix = pix.flatten().tolist() + + self.command(0x36) + self.data(0x70) + self.SetWindows(0, 0, self.height, self.width) + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + for i in range(0, len(pix), 4096): + self.spi_writebyte(pix[i:i+4096]) + + else: + img = self.np.asarray(Image) + pix = self.np.zeros((imheight, imwidth, 2), dtype=self.np.uint8) + + pix[...,[0]] = self.np.add(self.np.bitwise_and(img[...,[0]],0xF8),self.np.right_shift(img[...,[1]],5)) + pix[...,[1]] = self.np.add(self.np.bitwise_and(self.np.left_shift(img[...,[1]],3),0xE0), self.np.right_shift(img[...,[2]],3)) + + pix = pix.flatten().tolist() + + self.command(0x36) + self.data(0x00) + self.SetWindows(0, 0, self.width, self.height) + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + for i in range(0, len(pix), 4096): + self.spi_writebyte(pix[i:i+4096]) + + def clear(self): + """Clear contents of image buffer""" + _buffer = [0xff]*(self.width * self.height * 2) + self.SetWindows(0, 0, self.width, self.height) + self.digital_write(self.DC_PIN, self.GPIO.HIGH) + for i in range(0, len(_buffer), 4096): + self.spi_writebyte(_buffer[i:i+4096]) diff --git a/feed/waveshare-demo/src/waveshare/lib/__init__.py b/feed/waveshare-demo/src/waveshare/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/feed/waveshare-demo/src/waveshare/lib/lcdconfig.py b/feed/waveshare-demo/src/waveshare/lib/lcdconfig.py new file mode 100644 index 0000000..40ae025 --- /dev/null +++ b/feed/waveshare-demo/src/waveshare/lib/lcdconfig.py @@ -0,0 +1,118 @@ +# /***************************************************************************** +# * | File : epdconfig.py +# * | Author : Waveshare team +# * | Function : Hardware underlying interface +# * | Info : +# *---------------- +# * | This version: V1.0 +# * | Date : 2019-06-21 +# * | Info : +# ****************************************************************************** +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +import logging +import time + +import spidev + + +class RaspberryPi: + def __init__( + self, spi=spidev.SpiDev(0, 0), spi_freq=40000000, rst=27, dc=25, bl=18, + fan=19, bl_freq=1000, i2c=None, i2c_freq=100000 + ): + import RPi.GPIO + import numpy as np + + self.np = np + self.RST_PIN = rst + self.DC_PIN = dc + self.BL_PIN = bl + self.FAN_PIN = fan + self.SPEED = spi_freq + self.BL_freq = bl_freq + self.GPIO = RPi.GPIO + # self.GPIO.cleanup() + self.GPIO.setmode(self.GPIO.BCM) + self.GPIO.setwarnings(False) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) + self.GPIO.output(self.BL_PIN, self.GPIO.HIGH) + # Initialize SPI + self.SPI = spi + if self.SPI is not None: + self.SPI.max_speed_hz = spi_freq + self.SPI.mode = 0b00 + + def digital_write(self, pin, value): + self.GPIO.output(pin, value) + + def digital_read(self, pin): + return self.GPIO.input(pin) + + def delay_ms(self, delaytime): + time.sleep(delaytime / 1000.0) + + def spi_writebyte(self, data): + if self.SPI is not None: + self.SPI.writebytes(data) + + def bl_DutyCycle(self, duty): + self._pwm.ChangeDutyCycle(duty) + + def bl_Frequency(self, freq): + self._pwm.ChangeFrequency(freq) + + def module_init(self): + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) + self.GPIO.setup(self.FAN_PIN, self.GPIO.OUT) + # self.GPIO.output(self.FAN_PIN, 1) + self._pwm = self.GPIO.PWM(self.BL_PIN, self.BL_freq) + self._pwm.start(100) + self._pwm1 = self.GPIO.PWM(self.FAN_PIN, self.BL_freq) + self._pwm1.start(75) + if self.SPI is not None: + self.SPI.max_speed_hz = self.SPEED + self.SPI.mode = 0b00 + return 0 + + def module_exit(self): + logging.debug("spi end") + if self.SPI is not None: + self.SPI.close() + + logging.debug("gpio cleanup...") + self.GPIO.output(self.RST_PIN, 1) + self.GPIO.output(self.DC_PIN, 0) + self._pwm.stop() + self._pwm1.stop() + # self.GPIO.cleanup() + + +''' +if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'): + implementation = RaspberryPi() + +for func in [x for x in dir(implementation) if not x.startswith('_')]: + setattr(sys.modules[__name__], func, getattr(implementation, func)) +''' diff --git a/feed/waveshare-demo/src/waveshare/main.py b/feed/waveshare-demo/src/waveshare/main.py new file mode 100644 index 0000000..97e2be3 --- /dev/null +++ b/feed/waveshare-demo/src/waveshare/main.py @@ -0,0 +1,19 @@ +''' +Select images as required +True for image1 +False for image2 +''' + +import time + +from . import image + + +Img = image.image() + +while True: + if Img.flgh: + Img.HMI1() + else: + Img.HMI2() + time.sleep(1)