import requests import os import sys def byteToStr(v): return chr((v & 0xF) + 97) + chr(((v >> 4) & 0xF) + 97) def wordToStr(v): return byteToStr(v & 0xFF) + byteToStr((v >> 8) & 0xFF) # Reimplementation of u_data from scriptD.js def _u_data(pixel_indices, c, px_ind_start): rqMsg = "" pxInd = px_ind_start max_rq_len = 1000 # Max length of rqMsg if c == -1: # 16-bit values while pxInd < len(pixel_indices) and len(rqMsg) < max_rq_len: v = 0 for i in range(0, 16, 2): # This means 8 iterations, packing 8 pixels if pxInd < len(pixel_indices): v |= ( pixel_indices[pxInd] << i ) # This is likely wrong, should be 4 bits per pixel pxInd += 1 rqMsg += wordToStr(v) elif c == -2: # 7-color, 4-bit values while pxInd < len(pixel_indices) and len(rqMsg) < max_rq_len: v = 0 for i in range(0, 16, 4): # 4 iterations, packing 4 pixels if pxInd < len(pixel_indices): v |= pixel_indices[pxInd] << i pxInd += 1 rqMsg += wordToStr(v) else: # Monochrome, 1-bit values while pxInd < len(pixel_indices) and len(rqMsg) < max_rq_len: v = 0 for i in range(8): # Packs 8 pixels into 1 byte if pxInd < len(pixel_indices) and pixel_indices[pxInd] != c: v |= 128 >> i pxInd += 1 rqMsg += byteToStr(v) return rqMsg, pxInd # Reimplementation of u_line from scriptD.js def _u_line(pixel_indices, c, px_ind_start): rqMsg = "" pxInd = px_ind_start max_rq_len = 1000 # Max length of rqMsg while len(rqMsg) < max_rq_len: x = 0 while x < 122: # Processes 122 pixels at a time v = 0 for i in range(8): if pxInd < len(pixel_indices) and x < 122: if pixel_indices[pxInd] != c: v |= 128 >> i pxInd += 1 x += 1 else: break # Break if no more pixels or 122 pixels processed rqMsg += byteToStr(v) if x >= 122: # If 122 pixels processed, break inner loop break return rqMsg, pxInd def upload_image(img, ip_addr, epd_ind, epdArr, palArr, getNear): print(f"[DEBUG] Starting upload_image for EPD index {epd_ind} to {ip_addr}") url_prefix = f"http://{ip_addr}/" w, h = img.size pal_ind = epdArr[epd_ind][2] curPal = palArr[pal_ind] pixels = list(img.getdata()) pixel_indices = [getNear(r, g, b, curPal) for r, g, b in pixels] pxInd = 0 stInd = 0 def u_send(cmd, next_state=False): nonlocal stInd full_url = url_prefix + cmd try: response = requests.post(full_url) response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx) if next_state: stInd += 1 return 0 except requests.exceptions.RequestException as e: print(f"[ERROR] Error sending command {cmd}: {e}") raise # Re-raise the exception to stop execution def u_next(): nonlocal pxInd pxInd = 0 return u_send("NEXT_", True) def u_done(): sys.stdout.write("\n") # Ensure progress bar finishes on a new line print("Image upload complete!") return u_send("SHOW_", True) def u_show(a_len, k1, k2, rqMsg_val): nonlocal pxInd total_pixels = len(pixel_indices) current_progress_pixels = pxInd overall_percentage = ( (current_progress_pixels / total_pixels) * 100 if total_pixels > 0 else 0 ) bar_length = 50 filled_length = int(bar_length * overall_percentage // 100) bar = "#" * filled_length + "-" * (bar_length - filled_length) sys.stdout.write(f"\rProgress: |{bar}| {overall_percentage:.2f}%") sys.stdout.flush() return u_send(rqMsg_val + wordToStr(len(rqMsg_val)) + "LOAD_", pxInd >= a_len) # Main upload logic based on scriptD.js try: # Initial EPD command epd_cmd_char = chr(epd_ind + 97) if epd_ind < 26 else chr(epd_ind - 26 + 65) u_send(f"EPD{epd_cmd_char}_") # Conditional logic based on epd_ind, mimicking scriptD.js if epd_ind in [3, 39, 43]: # u_line flow while True: if stInd == 0: rqMsg, pxInd = _u_line(pixel_indices, 0, pxInd) u_show(len(pixel_indices), 0, 100, rqMsg) elif stInd == 1: u_done() break elif epd_ind == 40: # u_line with u_next flow while True: if stInd == 0: rqMsg, pxInd = _u_line(pixel_indices, 0, pxInd) u_show(len(pixel_indices), 0, 50, rqMsg) elif stInd == 1: u_next() elif stInd == 2: rqMsg, pxInd = _u_line(pixel_indices, 3, pxInd) u_show(len(pixel_indices), 50, 50, rqMsg) elif stInd == 3: u_done() break elif epd_ind in [0, 3, 6, 7, 9, 12, 16, 19, 22, 26, 27, 28]: # u_data flow (monochrome) while True: if stInd == 0: rqMsg, pxInd = _u_data(pixel_indices, 0, pxInd) u_show(len(pixel_indices), 0, 100, rqMsg) elif stInd == 1: u_done() break elif 15 < epd_ind < 22: # u_data flow (16-bit values, c=-1) while True: if stInd == 0: rqMsg, pxInd = _u_data(pixel_indices, -1, pxInd) u_show(len(pixel_indices), 0, 100, rqMsg) elif stInd == 1: u_done() break elif epd_ind in [25, 37]: # u_data flow (7-color, c=-2) while True: if stInd == 0: rqMsg, pxInd = _u_data(pixel_indices, -2, pxInd) u_show(len(pixel_indices), 0, 100, rqMsg) elif stInd == 1: u_done() break else: # Default u_data flow with u_next while True: if stInd == 0: c_val = -1 if epd_ind in [1, 12] else 0 rqMsg, pxInd = _u_data(pixel_indices, c_val, pxInd) u_show(len(pixel_indices), 0, 50, rqMsg) elif stInd == 1: u_next() elif stInd == 2: # Special handling for 7.5b V2 (epd_ind 23) red channel if epd_ind == 23: # Encode only red pixels (palette index 2) red_pixel_indices = [ 0 if p == 2 else 2 for p in pixel_indices ] # Invert red channel: 0 for red, 2 for non-red rqMsg, pxInd = _u_data( red_pixel_indices, 0, pxInd ) # Use monochrome encoding for this layer else: rqMsg, pxInd = _u_data(pixel_indices, 3, pxInd) u_show(len(pixel_indices), 50, 50, rqMsg) elif stInd == 3: u_done() break print("Image uploaded successfully!") except requests.exceptions.RequestException as e: print(f"[ERROR] Error during image upload: {e}") except Exception as e: print(f"[ERROR] An unexpected error occurred during upload: {e}")