diff --git a/pwnagotchi/ui/hw/libs/waveshare/v27inch/epd2in7.py b/pwnagotchi/ui/hw/libs/waveshare/v27inch/epd2in7.py
index 01e8473..20f1665 100644
--- a/pwnagotchi/ui/hw/libs/waveshare/v27inch/epd2in7.py
+++ b/pwnagotchi/ui/hw/libs/waveshare/v27inch/epd2in7.py
@@ -1,33 +1,13 @@
-# /*****************************************************************************
-# * | File        :	  EPD_1in54.py
+# *****************************************************************************
+# * | File        :	  epd2in7.py
 # * | Author      :   Waveshare team
 # * | Function    :   Electronic paper driver
 # * | Info        :
 # *----------------
-# * |	This version:   V3.0
-# * | Date        :   2018-11-06
-# * | Info        :   python2 demo
-# * 1.Remove:
-#   digital_write(self, pin, value)
-#   digital_read(self, pin)
-#   delay_ms(self, delaytime)
-#   set_lut(self, lut)
-#   self.lut = self.lut_full_update
-# * 2.Change:
-#   display_frame -> TurnOnDisplay
-#   set_memory_area -> SetWindow
-#   set_memory_pointer -> SetCursor
-#   get_frame_buffer -> getbuffer
-#   set_frame_memory -> display
-# * 3.How to use
-#   epd = epd2in7.EPD()
-#   epd.init(epd.lut_full_update)
-#   image = Image.new('1', (epd1in54.EPD_WIDTH, epd1in54.EPD_HEIGHT), 255)
-#   ...
-#   drawing ......
-#   ...
-#   epd.display(getbuffer(image))
-# ******************************************************************************/
+# * | This version:   V4.0
+# * | Date        :   2019-06-20
+# # | Info        :   python demo
+# -----------------------------------------------------------------------------
 # 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
@@ -47,64 +27,31 @@
 # THE SOFTWARE.
 #
 
-
+import logging
 from . import epdconfig
-from PIL import Image
-import RPi.GPIO as GPIO
 
 # Display resolution
 EPD_WIDTH       = 176
 EPD_HEIGHT      = 264
 
-# EPD2IN7 commands
-PANEL_SETTING                               = 0x00
-POWER_SETTING                               = 0x01
-POWER_OFF                                   = 0x02
-POWER_OFF_SEQUENCE_SETTING                  = 0x03
-POWER_ON                                    = 0x04
-POWER_ON_MEASURE                            = 0x05
-BOOSTER_SOFT_START                          = 0x06
-DEEP_SLEEP                                  = 0x07
-DATA_START_TRANSMISSION_1                   = 0x10
-DATA_STOP                                   = 0x11
-DISPLAY_REFRESH                             = 0x12
-DATA_START_TRANSMISSION_2                   = 0x13
-PARTIAL_DATA_START_TRANSMISSION_1           = 0x14
-PARTIAL_DATA_START_TRANSMISSION_2           = 0x15
-PARTIAL_DISPLAY_REFRESH                     = 0x16
-LUT_FOR_VCOM                                = 0x20
-LUT_WHITE_TO_WHITE                          = 0x21
-LUT_BLACK_TO_WHITE                          = 0x22
-LUT_WHITE_TO_BLACK                          = 0x23
-LUT_BLACK_TO_BLACK                          = 0x24
-PLL_CONTROL                                 = 0x30
-TEMPERATURE_SENSOR_COMMAND                  = 0x40
-TEMPERATURE_SENSOR_CALIBRATION              = 0x41
-TEMPERATURE_SENSOR_WRITE                    = 0x42
-TEMPERATURE_SENSOR_READ                     = 0x43
-VCOM_AND_DATA_INTERVAL_SETTING              = 0x50
-LOW_POWER_DETECTION                         = 0x51
-TCON_SETTING                                = 0x60
-TCON_RESOLUTION                             = 0x61
-SOURCE_AND_GATE_START_SETTING               = 0x62
-GET_STATUS                                  = 0x71
-AUTO_MEASURE_VCOM                           = 0x80
-VCOM_VALUE                                  = 0x81
-VCM_DC_SETTING_REGISTER                     = 0x82
-PROGRAM_MODE                                = 0xA0
-ACTIVE_PROGRAM                              = 0xA1
-READ_OTP_DATA                               = 0xA2
-
+GRAY1  = 0xff #white
+GRAY2  = 0xC0
+GRAY3  = 0x80 #gray
+GRAY4  = 0x00 #Blackest
 class EPD:
     def __init__(self):
         self.reset_pin = epdconfig.RST_PIN
         self.dc_pin = epdconfig.DC_PIN
         self.busy_pin = epdconfig.BUSY_PIN
+        self.cs_pin = epdconfig.CS_PIN
         self.width = EPD_WIDTH
         self.height = EPD_HEIGHT
+        self.GRAY1  = GRAY1 #white
+        self.GRAY2  = GRAY2
+        self.GRAY3  = GRAY3 #gray
+        self.GRAY4  = GRAY4 #Blackest
 
-    lut_vcom_dc = [
-        0x00, 0x00,
+    lut_vcom_dc = [0x00, 0x00,
         0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
         0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
         0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
@@ -148,147 +95,418 @@ class EPD:
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ]    
+    ]
+    ###################full screen update LUT######################
+    #0~3 gray
+    gray_lut_vcom = [
+    0x00, 0x00,
+    0x00, 0x0A, 0x00, 0x00, 0x00, 0x01,
+    0x60, 0x14, 0x14, 0x00, 0x00, 0x01,
+    0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x13, 0x0A, 0x01, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,				
+    ]
+    #R21
+    gray_lut_ww =[
+    0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
+    0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
+    0x10, 0x14, 0x0A, 0x00, 0x00, 0x01,
+    0xA0, 0x13, 0x01, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    ]
+    #R22H	r
+    gray_lut_bw =[
+    0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
+    0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
+    0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
+    0x99, 0x0C, 0x01, 0x03, 0x04, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    ]
+    #R23H	w
+    gray_lut_wb =[
+    0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
+    0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
+    0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
+    0x99, 0x0B, 0x04, 0x04, 0x01, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    ]
+    #R24H	b
+    gray_lut_bb =[
+    0x80, 0x0A, 0x00, 0x00, 0x00, 0x01,
+    0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
+    0x20, 0x14, 0x0A, 0x00, 0x00, 0x01,
+    0x50, 0x13, 0x01, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    ]
+    
     # Hardware reset
     def reset(self):
-        epdconfig.digital_write(self.reset_pin, GPIO.HIGH)
+        epdconfig.digital_write(self.reset_pin, 1)
         epdconfig.delay_ms(200) 
-        epdconfig.digital_write(self.reset_pin, GPIO.LOW)         # module reset
-        epdconfig.delay_ms(200)
-        epdconfig.digital_write(self.reset_pin, GPIO.HIGH)
+        epdconfig.digital_write(self.reset_pin, 0)
+        epdconfig.delay_ms(10)
+        epdconfig.digital_write(self.reset_pin, 1)
         epdconfig.delay_ms(200)   
 
     def send_command(self, command):
-        epdconfig.digital_write(self.dc_pin, GPIO.LOW)
+        epdconfig.digital_write(self.dc_pin, 0)
+        epdconfig.digital_write(self.cs_pin, 0)
         epdconfig.spi_writebyte([command])
+        epdconfig.digital_write(self.cs_pin, 1)
 
     def send_data(self, data):
-        epdconfig.digital_write(self.dc_pin, GPIO.HIGH)
+        epdconfig.digital_write(self.dc_pin, 1)
+        epdconfig.digital_write(self.cs_pin, 0)
         epdconfig.spi_writebyte([data])
+        epdconfig.digital_write(self.cs_pin, 1)
         
-    def wait_until_idle(self):        
-        while(epdconfig.digital_read(self.busy_pin) == 0):      # 0: idle, 1: busy
-            self.send_command(0x71)
-        epdconfig.delay_ms(100)    
+    def ReadBusy(self):        
+        logging.debug("e-Paper busy")
+        while(epdconfig.digital_read(self.busy_pin) == 0):      #  0: idle, 1: busy
+            epdconfig.delay_ms(200)                
+        logging.debug("e-Paper busy release")
 
     def set_lut(self):
-        self.send_command(LUT_FOR_VCOM)               # vcom
+        self.send_command(0x20) # vcom
         for count in range(0, 44):
             self.send_data(self.lut_vcom_dc[count])
-        self.send_command(LUT_WHITE_TO_WHITE)         # ww --
+        self.send_command(0x21) # ww --
         for count in range(0, 42):
             self.send_data(self.lut_ww[count])
-        self.send_command(LUT_BLACK_TO_WHITE)         # bw r
+        self.send_command(0x22) # bw r
         for count in range(0, 42):
             self.send_data(self.lut_bw[count])
-        self.send_command(LUT_WHITE_TO_BLACK)         # wb w
+        self.send_command(0x23) # wb w
         for count in range(0, 42):
             self.send_data(self.lut_bb[count])
-        self.send_command(LUT_BLACK_TO_BLACK)         # bb b
+        self.send_command(0x24) # bb b
         for count in range(0, 42):
             self.send_data(self.lut_wb[count])
             
+    def gray_SetLut(self):
+        self.send_command(0x20)
+        for count in range(0, 44):        #vcom
+            self.send_data(self.gray_lut_vcom[count])
+            
+        self.send_command(0x21)							#red not use
+        for count in range(0, 42): 
+            self.send_data(self.gray_lut_ww[count])
+
+        self.send_command(0x22)							#bw r
+        for count in range(0, 42): 
+            self.send_data(self.gray_lut_bw[count])
+
+        self.send_command(0x23)							#wb w
+        for count in range(0, 42): 
+            self.send_data(self.gray_lut_wb[count])
+
+        self.send_command(0x24)							#bb b
+        for count in range(0, 42): 
+            self.send_data(self.gray_lut_bb[count])
+
+        self.send_command(0x25)							#vcom
+        for count in range(0, 42): 
+            self.send_data(self.gray_lut_ww[count])
+    
     def init(self):
         if (epdconfig.module_init() != 0):
             return -1
+            
         # EPD hardware init start
         self.reset()
-        self.send_command(POWER_SETTING)
-        self.send_data(0x03)                  # VDS_EN, VDG_EN
-        self.send_data(0x00)                  # VCOM_HV, VGHL_LV[1], VGHL_LV[0]
-        self.send_data(0x2b)                  # VDH
-        self.send_data(0x2b)                  # VDL
-        self.send_data(0x09)                  # VDHR
-        self.send_command(BOOSTER_SOFT_START)
+        
+        self.send_command(0x01) # POWER_SETTING
+        self.send_data(0x03) # VDS_EN, VDG_EN
+        self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0]
+        self.send_data(0x2b) # VDH
+        self.send_data(0x2b) # VDL
+        self.send_data(0x09) # VDHR
+        
+        self.send_command(0x06) # BOOSTER_SOFT_START
         self.send_data(0x07)
         self.send_data(0x07)
         self.send_data(0x17)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0x60)
         self.send_data(0xA5)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0x89)
         self.send_data(0xA5)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0x90)
         self.send_data(0x00)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0x93)
         self.send_data(0x2A)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0xA0)
         self.send_data(0xA5)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0xA1)
         self.send_data(0x00)
+        
         # Power optimization
         self.send_command(0xF8)
         self.send_data(0x73)
         self.send_data(0x41)
-        self.send_command(PARTIAL_DISPLAY_REFRESH)
+        
+        self.send_command(0x16) # PARTIAL_DISPLAY_REFRESH
         self.send_data(0x00)
-        self.send_command(POWER_ON)
-        self.wait_until_idle()
+        self.send_command(0x04) # POWER_ON
+        self.ReadBusy()
 
-        self.send_command(PANEL_SETTING)
-        self.send_data(0xAF)        # KW-BF   KWR-AF    BWROTP 0f
-        self.send_command(PLL_CONTROL)
-        self.send_data(0x3A)        # 3A 100HZ   29 150Hz 39 200HZ    31 171HZ
-        self.send_command(VCM_DC_SETTING_REGISTER)
+        self.send_command(0x00) # PANEL_SETTING
+        self.send_data(0xAF) # KW-BF   KWR-AF    BWROTP 0f
+        
+        self.send_command(0x30) # PLL_CONTROL
+        self.send_data(0x3A) # 3A 100HZ   29 150Hz 39 200HZ    31 171HZ
+        
+        self.send_command(0x82) # VCM_DC_SETTING_REGISTER
         self.send_data(0x12)
         self.set_lut()
-        # EPD hardware init end
         return 0
 
+    def Init_4Gray(self):
+        if (epdconfig.module_init() != 0):
+            return -1
+        self.reset()
+        
+        self.send_command(0x01)			#POWER SETTING
+        self.send_data (0x03)
+        self.send_data (0x00)    
+        self.send_data (0x2b)															 
+        self.send_data (0x2b)		
+
+
+        self.send_command(0x06)         #booster soft start
+        self.send_data (0x07)		#A
+        self.send_data (0x07)		#B
+        self.send_data (0x17)		#C 
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0x60)
+        self.send_data (0xA5)
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0x89)
+        self.send_data (0xA5)
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0x90)
+        self.send_data (0x00)
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0x93)
+        self.send_data (0x2A)
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0xa0)
+        self.send_data (0xa5)
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0xa1)
+        self.send_data (0x00)
+
+        self.send_command(0xF8)         #boost??
+        self.send_data (0x73)
+        self.send_data (0x41)
+
+        self.send_command(0x16)
+        self.send_data(0x00)	
+
+        self.send_command(0x04)
+        self.ReadBusy()
+
+        self.send_command(0x00)			#panel setting
+        self.send_data(0xbf)		#KW-BF   KWR-AF	BWROTP 0f
+
+        self.send_command(0x30)			#PLL setting
+        self.send_data (0x90)      	#100hz 
+
+        self.send_command(0x61)			#resolution setting
+        self.send_data (0x00)		#176
+        self.send_data (0xb0)     	 
+        self.send_data (0x01)		#264
+        self.send_data (0x08)
+
+        self.send_command(0x82)			#vcom_DC setting
+        self.send_data (0x12)
+
+        self.send_command(0X50)			#VCOM AND DATA INTERVAL SETTING			
+        self.send_data(0x97)
+
     def getbuffer(self, image):
-        # print "bufsiz = ",(self.width/8) * self.height
-        buf = [0xFF] * ((self.width//8) * self.height)
+        # logging.debug("bufsiz = ",int(self.width/8) * self.height)
+        buf = [0xFF] * (int(self.width/8) * self.height)
         image_monocolor = image.convert('1')
         imwidth, imheight = image_monocolor.size
         pixels = image_monocolor.load()
-        # print "imwidth = %d, imheight = %d",imwidth,imheight
+        # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
         if(imwidth == self.width and imheight == self.height):
-            print("Vertical")
+            logging.debug("Vertical")
             for y in range(imheight):
                 for x in range(imwidth):
                     # Set the bits for the column of pixels at the current position.
                     if pixels[x, y] == 0:
-                        buf[(x + y * self.width) // 8] &= ~(0x80 >> (x % 8))
+                        buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
         elif(imwidth == self.height and imheight == self.width):
-            print("Horizontal")
+            logging.debug("Horizontal")
             for y in range(imheight):
                 for x in range(imwidth):
                     newx = y
                     newy = self.height - x - 1
                     if pixels[x, y] == 0:
-                        buf[(newx + newy*self.width) // 8] &= ~(0x80 >> (y % 8))
+                        buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
         return buf
-
+    
+    def getbuffer_4Gray(self, image):
+        # logging.debug("bufsiz = ",int(self.width/8) * self.height)
+        buf = [0xFF] * (int(self.width / 4) * self.height)
+        image_monocolor = image.convert('L')
+        imwidth, imheight = image_monocolor.size
+        pixels = image_monocolor.load()
+        i=0
+        # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
+        if(imwidth == self.width and imheight == self.height):
+            logging.debug("Vertical")
+            for y in range(imheight):
+                for x in range(imwidth):
+                    # Set the bits for the column of pixels at the current position.
+                    if(pixels[x, y] == 0xC0):
+                        pixels[x, y] = 0x80
+                    elif (pixels[x, y] == 0x80):
+                        pixels[x, y] = 0x40
+                    i= i+1
+                    if(i%4 == 0):
+                        buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6)
+                        
+        elif(imwidth == self.height and imheight == self.width):
+            logging.debug("Horizontal")
+            for x in range(imwidth):
+                for y in range(imheight):
+                    newx = y
+                    newy = x
+                    if(pixels[x, y] == 0xC0):
+                        pixels[x, y] = 0x80
+                    elif (pixels[x, y] == 0x80):
+                        pixels[x, y] = 0x40
+                    i= i+1
+                    if(i%4 == 0):
+                        buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6) 
+        return buf
+    
     def display(self, image):
-        self.send_command(DATA_START_TRANSMISSION_1)
-        for i in range(0, self.width * self.height // 8):
+        self.send_command(0x10)
+        for i in range(0, int(self.width * self.height / 8)):
             self.send_data(0xFF)
-        self.send_command(DATA_START_TRANSMISSION_2)
-        for i in range(0, self.width * self.height // 8):
+        self.send_command(0x13)
+        for i in range(0, int(self.width * self.height / 8)):
             self.send_data(image[i])
-        self.send_command(DISPLAY_REFRESH) 
-        self.wait_until_idle()
+        self.send_command(0x12) 
+        self.ReadBusy()
+
+    def display_4Gray(self, image):
+        self.send_command(0x10)
+        for i in range(0, 5808):                     #5808*4  46464
+            temp3=0
+            for j in range(0, 2):
+                temp1 = image[i*2+j]
+                for k in range(0, 2):
+                    temp2 = temp1&0xC0 
+                    if(temp2 == 0xC0):
+                        temp3 |= 0x01#white
+                    elif(temp2 == 0x00):
+                        temp3 |= 0x00  #black
+                    elif(temp2 == 0x80): 
+                        temp3 |= 0x01  #gray1
+                    else: #0x40
+                        temp3 |= 0x00 #gray2
+                    temp3 <<= 1	
+                    
+                    temp1 <<= 2
+                    temp2 = temp1&0xC0 
+                    if(temp2 == 0xC0):  #white
+                        temp3 |= 0x01
+                    elif(temp2 == 0x00): #black
+                        temp3 |= 0x00
+                    elif(temp2 == 0x80):
+                        temp3 |= 0x01 #gray1
+                    else :   #0x40
+                            temp3 |= 0x00	#gray2	
+                    if(j!=1 or k!=1):				
+                        temp3 <<= 1
+                    temp1 <<= 2
+            self.send_data(temp3)
+            
+        self.send_command(0x13)	       
+        for i in range(0, 5808):                #5808*4  46464
+            temp3=0
+            for j in range(0, 2):
+                temp1 = image[i*2+j]
+                for k in range(0, 2):
+                    temp2 = temp1&0xC0 
+                    if(temp2 == 0xC0):
+                        temp3 |= 0x01#white
+                    elif(temp2 == 0x00):
+                        temp3 |= 0x00  #black
+                    elif(temp2 == 0x80):
+                        temp3 |= 0x00  #gray1
+                    else: #0x40
+                        temp3 |= 0x01 #gray2
+                    temp3 <<= 1	
+                    
+                    temp1 <<= 2
+                    temp2 = temp1&0xC0 
+                    if(temp2 == 0xC0):  #white
+                        temp3 |= 0x01
+                    elif(temp2 == 0x00): #black
+                        temp3 |= 0x00
+                    elif(temp2 == 0x80):
+                        temp3 |= 0x00 #gray1
+                    else:    #0x40
+                            temp3 |= 0x01	#gray2
+                    if(j!=1 or k!=1):					
+                        temp3 <<= 1
+                    temp1 <<= 2
+            self.send_data(temp3)
+        
+        self.gray_SetLut()
+        self.send_command(0x12)
+        epdconfig.delay_ms(200)
+        self.ReadBusy()
+        # pass
         
     def Clear(self, color):
-        self.send_command(DATA_START_TRANSMISSION_1)
-        for i in range(0, self.width * self.height // 8):
+        self.send_command(0x10)
+        for i in range(0, int(self.width * self.height / 8)):
             self.send_data(0xFF)
-        self.send_command(DATA_START_TRANSMISSION_2)
-        for i in range(0, self.width * self.height // 8):
+        self.send_command(0x13)
+        for i in range(0, int(self.width * self.height / 8)):
             self.send_data(0xFF)
-        self.send_command(DISPLAY_REFRESH) 
-        self.wait_until_idle()
+        self.send_command(0x12) 
+        self.ReadBusy()
 
     def sleep(self):
         self.send_command(0X50)
@@ -296,5 +514,7 @@ class EPD:
         self.send_command(0X02)
         self.send_command(0X07)
         self.send_data(0xA5)
+        
+        epdconfig.module_exit()
 ### END OF FILE ###
 
diff --git a/pwnagotchi/ui/hw/libs/waveshare/v27inch/epdconfig.py b/pwnagotchi/ui/hw/libs/waveshare/v27inch/epdconfig.py
index 78ff647..861f43d 100644
--- a/pwnagotchi/ui/hw/libs/waveshare/v27inch/epdconfig.py
+++ b/pwnagotchi/ui/hw/libs/waveshare/v27inch/epdconfig.py
@@ -1,19 +1,13 @@
 # /*****************************************************************************
-# * | File        :	  EPD_1in54.py
+# * | File        :	  epdconfig.py
 # * | Author      :   Waveshare team
 # * | Function    :   Hardware underlying interface
 # * | Info        :
 # *----------------
-# * |	This version:   V2.0
-# * | Date        :   2018-11-01
+# * | This version:   V1.0
+# * | Date        :   2019-06-21
 # * | Info        :   
-# * 1.Remove:
-#   digital_write(self, pin, value)
-#   digital_read(self, pin)
-#   delay_ms(self, delaytime)
-#   set_lut(self, lut)
-#   self.lut = self.lut_full_update
-# ******************************************************************************/
+# ******************************************************************************
 # 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
@@ -33,41 +27,128 @@
 # THE SOFTWARE.
 #
 
-
-import spidev
-import RPi.GPIO as GPIO
+import os
+import logging
+import sys
 import time
 
-# Pin definition
-RST_PIN         = 17
-DC_PIN          = 25
-CS_PIN          = 8
-BUSY_PIN        = 24
 
-# SPI device, bus = 0, device = 0
-SPI = spidev.SpiDev(0, 0)
+class RaspberryPi:
+    # Pin definition
+    RST_PIN         = 17
+    DC_PIN          = 25
+    CS_PIN          = 8
+    BUSY_PIN        = 24
 
-def digital_write(pin, value):
-    GPIO.output(pin, value)
+    def __init__(self):
+        import spidev
+        import RPi.GPIO
 
-def digital_read(pin):
-    return GPIO.input(BUSY_PIN)
+        self.GPIO = RPi.GPIO
 
-def delay_ms(delaytime):
-    time.sleep(delaytime / 1000.0)
+        # SPI device, bus = 0, device = 0
+        self.SPI = spidev.SpiDev(0, 0)
 
-def spi_writebyte(data):
-    SPI.writebytes(data)
+    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):
+        self.SPI.writebytes(data)
+
+    def module_init(self):
+        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.CS_PIN, self.GPIO.OUT)
+        self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
+        self.SPI.max_speed_hz = 4000000
+        self.SPI.mode = 0b00
+        return 0
+
+    def module_exit(self):
+        logging.debug("spi end")
+        self.SPI.close()
+
+        logging.debug("close 5V, Module enters 0 power consumption ...")
+        self.GPIO.output(self.RST_PIN, 0)
+        self.GPIO.output(self.DC_PIN, 0)
+
+        self.GPIO.cleanup()
+
+
+class JetsonNano:
+    # Pin definition
+    RST_PIN         = 17
+    DC_PIN          = 25
+    CS_PIN          = 8
+    BUSY_PIN        = 24
+
+    def __init__(self):
+        import ctypes
+        find_dirs = [
+            os.path.dirname(os.path.realpath(__file__)),
+            '/usr/local/lib',
+            '/usr/lib',
+        ]
+        self.SPI = None
+        for find_dir in find_dirs:
+            so_filename = os.path.join(find_dir, 'sysfs_software_spi.so')
+            if os.path.exists(so_filename):
+                self.SPI = ctypes.cdll.LoadLibrary(so_filename)
+                break
+        if self.SPI is None:
+            raise RuntimeError('Cannot find sysfs_software_spi.so')
+
+        import Jetson.GPIO
+        self.GPIO = Jetson.GPIO
+
+    def digital_write(self, pin, value):
+        self.GPIO.output(pin, value)
+
+    def digital_read(self, pin):
+        return self.GPIO.input(self.BUSY_PIN)
+
+    def delay_ms(self, delaytime):
+        time.sleep(delaytime / 1000.0)
+
+    def spi_writebyte(self, data):
+        self.SPI.SYSFS_software_spi_transfer(data[0])
+
+    def module_init(self):
+        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.CS_PIN, self.GPIO.OUT)
+        self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
+        self.SPI.SYSFS_software_spi_begin()
+        return 0
+
+    def module_exit(self):
+        logging.debug("spi end")
+        self.SPI.SYSFS_software_spi_end()
+
+        logging.debug("close 5V, Module enters 0 power consumption ...")
+        self.GPIO.output(self.RST_PIN, 0)
+        self.GPIO.output(self.DC_PIN, 0)
+
+        self.GPIO.cleanup()
+
+
+if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
+    implementation = RaspberryPi()
+else:
+    implementation = JetsonNano()
+
+for func in [x for x in dir(implementation) if not x.startswith('_')]:
+    setattr(sys.modules[__name__], func, getattr(implementation, func))
 
-def module_init():
-    GPIO.setmode(GPIO.BCM)
-    GPIO.setwarnings(False)
-    GPIO.setup(RST_PIN, GPIO.OUT)
-    GPIO.setup(DC_PIN, GPIO.OUT)
-    GPIO.setup(CS_PIN, GPIO.OUT)
-    GPIO.setup(BUSY_PIN, GPIO.IN)
-    SPI.max_speed_hz = 2000000
-    SPI.mode = 0b00
-    return 0;
 
 ### END OF FILE ###