From 8122ae342b5ee7a8aad1d1edbb0b5e9feee0d637 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Wed, 26 Jun 2024 16:33:15 +0100 Subject: [PATCH 1/6] remove GSM page and start on network connectivity --- emonPiLCD2.py | 80 ++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/emonPiLCD2.py b/emonPiLCD2.py index a547e70..eea1b58 100755 --- a/emonPiLCD2.py +++ b/emonPiLCD2.py @@ -92,8 +92,20 @@ # ------------------------------------------------------------------------------------ # Default Startup Page -max_number_pages = 8 page = default_page + +# Define pages in array +pages = [ + "Ethernet", + "WiFi", + "WiFi AP", + "WiFi AP Toggle", + "SSH", + "Shutdown", + "System Info", + "Uptime" +] + screensaver = False sd_image_version = '' @@ -150,11 +162,11 @@ def drawText(x,y,msg,update=False): def buttonPressLong(): - global page + global page, pages logger.info("Mode button LONG press") - if page == 7: + if page == pages.index("SSH"): ret = subprocess.call(ssh_status, shell=True) if ret > 0: drawText(0,0,'Enabling SSH',True) @@ -173,11 +185,11 @@ def buttonPressLong(): drawText(0,0,'SSH Disabled') drawText(0,14,'',True) - elif page == 8: + elif page == pages.index("Shutdown"): logger.info("Shutting down") shutdown() - elif page == 5: + elif page == pages.index("WiFi AP Toggle"): ret = subprocess.call(wifiAP_status, shell=True) if ret == 0: logger.info("Stopping WiFi AP") @@ -186,7 +198,7 @@ def buttonPressLong(): time.sleep(1) drawText(0,0,'WiFi AP Stopped',True) time.sleep(1) - page = 4 + page = pages.index("WiFi AP") updateLCD() else: logger.info("Starting WiFi AP") @@ -195,11 +207,11 @@ def buttonPressLong(): time.sleep(3) drawText(0,0,'WiFi AP Started',True) time.sleep(1) - page = 4 + page = pages.index("WiFi AP") updateLCD() def buttonPress(): - global page + global page, pages global screensaver global buttonPress_time @@ -207,7 +219,7 @@ def buttonPress(): screensaver = False else: page += 1 - if page > max_number_pages: + if page > len(pages)-1: page = 0 now = time.time() @@ -221,7 +233,7 @@ def buttonPress(): def updateLCD(): # Lock thread to avoid LCD being corrupted if a button press interrupt interrupts the LCD update with lock: - global page + global page, pages global screensaver # Create object for getting IP addresses of interfaces @@ -231,11 +243,12 @@ def updateLCD(): drawClear(); return - if page == 0: + if page == pages.index("System Info"): drawText(0,0,sd_image_version) drawText(0,14,"Serial: " + serial_num,True) + return - if page == 1: + if page == pages.index("Uptime"): # Get uptime with open('/proc/uptime', 'r') as f: seconds = float(f.readline().split()[0]) @@ -243,9 +256,10 @@ def updateLCD(): drawText(0,0,datetime.now().strftime('%b %d %H:%M')) drawText(0,14,'Uptime %.2f days' % (seconds / 86400),True) + return # Now display the appropriate LCD page - if page == 2: + if page == pages.index("Ethernet"): # Update ethernet eth0ip = ipaddress.get_ip_address('eth0') r.set("eth:active", int(bool(eth0ip))) @@ -262,8 +276,9 @@ def updateLCD(): else: drawText(0,0,"Ethernet:") drawText(0,14,"NOT CONNECTED",True) + return - if page == 3: + if page == pages.index("WiFi"): # Update wifi wlan0ip = ipaddress.get_ip_address('wlan0') @@ -294,8 +309,9 @@ def updateLCD(): drawText(0,14,"NOT CONNECTED",True) oled.image(image) oled.show() + return - if page == 4: + if page == pages.index("WiFi AP"): ap0ip = ipaddress.get_ip_address('ap0') r.set("ap0:active", int(bool(ap0ip))) @@ -309,8 +325,10 @@ def updateLCD(): drawText(0,14,"DISABLED",True) oled.image(image) oled.show() + return - if page == 5: + + if page == pages.index("WiFi AP Toggle"): ret = subprocess.call(wifiAP_status, shell=True) if ret == 0: drawText(0,0,"Disable WiFi AP?") @@ -318,27 +336,9 @@ def updateLCD(): drawText(0,0,"Enable WiFi AP?") drawText(0,14,"Y press & hold",True) + return - if page == 6: - # Update Hi-Link 3G Dongle - connects on eth1 - if ipaddress.get_ip_address("eth1") and gsmhuaweistatus.is_hilink(hilink_device_ip): - gsm_connection_status = gsmhuaweistatus.return_gsm_connection_status(hilink_device_ip) - r.set("gsm:connection", gsm_connection_status[0]) - r.set("gsm:signal", gsm_connection_status[1]) - r.set("gsm:active", 1) - else: - r.set("gsm:active", 0) - - if eval(r.get("gsm:active")): - drawText(0,0,r.get("gsm:connection")) - drawText(0,14,r.get("gsm:signal"),True) - elif eval(r.get("eth:active")) or eval(r.get("wlan:active")): - page += 1 - else: - drawText(0,0,"GSM:") - drawText(0,14,"NO DEVICE",True) - - if page == 7: + if page == pages.index("SSH"): ret = subprocess.call(ssh_status, shell=True) if ret > 0: #ssh not running @@ -348,10 +348,12 @@ def updateLCD(): drawText(0,0,"SSH Disable?") drawText(0,14,"Y press & hold",True) + return - if page == 8: + if page == pages.index("Shutdown"): drawText(0,0,"Shutdown?") drawText(0,14,"Y press & hold",True) + return class IPAddress: @@ -583,7 +585,7 @@ def on_connect(client, userdata, flags, rc): if btn_state: press_time = math.floor(now - btn_press_timer) - if page==5 or page == 7 or page == 8: + if page == pages.index("WiFi AP Toggle") or page == pages.index("SSH") or page == pages.index("Shutdown"): if press_time>=1.0 and press_time<=5.0: draw.rectangle((108, 15, 120, 25), outline=0, fill=0) draw.text((110,14), str(press_time), font=font, fill=255) @@ -593,7 +595,7 @@ def on_connect(client, userdata, flags, rc): buttonPressLong() - if (now-buttonPress_time)>=59: + if (now-buttonPress_time)>=300: screensaver = True #Update LCD in case it is left at a screen where values can change (e.g uptime etc) From 0541ef4526879f2b479b36265057bfd1d2b9a6a3 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Wed, 26 Jun 2024 17:45:28 +0100 Subject: [PATCH 2/6] emonHP data page --- emonPiLCD2.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/emonPiLCD2.py b/emonPiLCD2.py index eea1b58..79e951f 100755 --- a/emonPiLCD2.py +++ b/emonPiLCD2.py @@ -16,6 +16,7 @@ import itertools import threading import math +import json import redis import paho.mqtt.client as mqtt @@ -96,6 +97,7 @@ # Define pages in array pages = [ + "emonHP Data", "Ethernet", "WiFi", "WiFi AP", @@ -235,6 +237,7 @@ def updateLCD(): with lock: global page, pages global screensaver + global r # Create object for getting IP addresses of interfaces ipaddress = IPAddress() @@ -243,6 +246,18 @@ def updateLCD(): drawClear(); return + # Load emoncms inputs from redis + inputs = {} + inputids = r.smembers('user:inputs:1') + for input in inputids: + input_obj = r.hgetall('input:' + input) + input_last_timevalue = r.hgetall('input:lastvalue:' + input) + # by nodeid and name + if input_obj['nodeid'] not in inputs: + inputs[input_obj['nodeid']] = {} + inputs[input_obj['nodeid']][input_obj['name']] = input_last_timevalue + + if page == pages.index("System Info"): drawText(0,0,sd_image_version) drawText(0,14,"Serial: " + serial_num,True) @@ -258,6 +273,37 @@ def updateLCD(): drawText(0,14,'Uptime %.2f days' % (seconds / 86400),True) return + # Display emonTx4 data + if page == pages.index("emonHP Data"): + nodeid = 'heatpump' + name = 'electric_Power' + if nodeid in inputs: + if name in inputs[nodeid] and 'value' in inputs[nodeid][name]: + updated_ago = time.time() - float(inputs[nodeid][name]['time']) + value = float(inputs[nodeid][name]['value']) + if updated_ago < 30: + # ELEC 0W (10s ago) + drawText(0,0,'ELEC: %.0fW (%ds ago)' % (value, updated_ago)) + else: + drawText(0,0,'ELEC: ERROR') + else: + drawText(0,0,'ELEC: ERROR') + + nodeid = 'heatpump' + name = 'heatmeter_Power' + if nodeid in inputs: + if name in inputs[nodeid] and 'value' in inputs[nodeid][name]: + updated_ago = time.time() - float(inputs[nodeid][name]['time']) + value = float(inputs[nodeid][name]['value']) + if updated_ago < 30: + # Heat 0W (10s ago) + drawText(0,14,'HEAT: %.0fW (%ds ago)' % (value, updated_ago),True) + else: + drawText(0,14,'HEAT: ERROR',True) + else: + drawText(0,14,'HEAT: ERROR',True) + return + # Now display the appropriate LCD page if page == pages.index("Ethernet"): # Update ethernet @@ -566,7 +612,7 @@ def on_connect(client, userdata, flags, rc): last_btn_state = btn_state btn_state = push_btn.is_pressed - + if btn_state != last_btn_state: if btn_state and not last_btn_state: @@ -599,7 +645,7 @@ def on_connect(client, userdata, flags, rc): screensaver = True #Update LCD in case it is left at a screen where values can change (e.g uptime etc) - if (now-lcd_update_time)>=10.0: + if (now-lcd_update_time)>=1.0: lcd_update_time = now updateLCD() From 6da7baaf835a87d7d9754475e007f376989624a8 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Tue, 27 May 2025 15:30:05 +0100 Subject: [PATCH 3/6] fix missing text if no unputs --- emonPiLCD2.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/emonPiLCD2.py b/emonPiLCD2.py index 36ad0ae..e0defb2 100755 --- a/emonPiLCD2.py +++ b/emonPiLCD2.py @@ -288,6 +288,8 @@ def updateLCD(): drawText(0,0,'ELEC: ERROR') else: drawText(0,0,'ELEC: ERROR') + else: + drawText(0,0,'ELEC: ERROR') nodeid = 'heatpump' name = 'heatmeter_Power' @@ -302,6 +304,8 @@ def updateLCD(): drawText(0,14,'HEAT: ERROR',True) else: drawText(0,14,'HEAT: ERROR',True) + else: + drawText(0,14,'HEAT: ERROR',True) return # Now display the appropriate LCD page @@ -655,3 +659,4 @@ def on_connect(client, userdata, flags, rc): if __name__ == '__main__': main() + From 0ad293082ea4813d1185b28a78c75fd1192ffdd0 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Tue, 27 May 2025 15:46:38 +0100 Subject: [PATCH 4/6] oled splash --- initramfs_splash/install.sh | 40 ++++++ initramfs_splash/oled | 14 ++ initramfs_splash/oled_boot.c | 233 ++++++++++++++++++++++++++++++++++ initramfs_splash/oled_display | 15 +++ 4 files changed, 302 insertions(+) create mode 100644 initramfs_splash/install.sh create mode 100644 initramfs_splash/oled create mode 100644 initramfs_splash/oled_boot.c create mode 100644 initramfs_splash/oled_display diff --git a/initramfs_splash/install.sh b/initramfs_splash/install.sh new file mode 100644 index 0000000..1ecb181 --- /dev/null +++ b/initramfs_splash/install.sh @@ -0,0 +1,40 @@ +echo "Installing OLED Boot Script..." + +# check that this is a Raspberry Pi 4 +if [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "armv7l" ]; then + echo "This script is intended for Raspberry Pi 4 only." + exit 1 +fi + +# change to the directory of the script +cd "$(dirname "$0")" +echo "Current directory: $(pwd)" + +# compile the C program +echo "Compiling oled_boot.c..." +gcc -o oled_boot oled_boot.c + +# check if the compilation was successful +if [ $? -ne 0 ]; then + echo "Compilation failed. Please check the source code for errors." + exit 1 +fi + +# copy the compiled binary to /usr/local/bin +echo "Copying oled_boot to /usr/local/bin..." +sudo cp oled_boot /usr/local/bin/oled_boot + +# copy oled to /etc/initramfs-tools/scripts/init-top/oled +echo "Copying oled script to /etc/initramfs-tools/scripts/init-top/oled..." +sudo mkdir -p /etc/initramfs-tools/scripts/init-top +sudo cp oled /etc/initramfs-tools/scripts/init-top/oled +sudo chmod +x /etc/initramfs-tools/scripts/init-top/oled + +# copy oled_display to /etc/initramfs-tools/scripts/oled_display +echo "Copying oled_display script to /etc/initramfs-tools/scripts/oled_display..." +sudo cp oled_display /etc/initramfs-tools/scripts/oled_display +sudo chmod +x /etc/initramfs-tools/scripts/oled_display + +# Update initramfs +echo "Updating initramfs..." +sudo update-initramfs -u -k $(uname -r) \ No newline at end of file diff --git a/initramfs_splash/oled b/initramfs_splash/oled new file mode 100644 index 0000000..5867811 --- /dev/null +++ b/initramfs_splash/oled @@ -0,0 +1,14 @@ +#!/bin/sh +PREREQ="" + +prereqs() { echo "$PREREQ"; } +case "$1" in + prereqs) prereqs; exit 0 ;; +esac + +modprobe i2c-bcm2835 +modprobe i2c-dev + +sleep 0.5 +lsmod > /run/oled.lsmod.txt +/usr/local/bin/oled_boot >> /run/oled.log 2>&1 diff --git a/initramfs_splash/oled_boot.c b/initramfs_splash/oled_boot.c new file mode 100644 index 0000000..ee251f8 --- /dev/null +++ b/initramfs_splash/oled_boot.c @@ -0,0 +1,233 @@ +// Simple OLED Splash Screen for emonHP +// Author: Trystan Lea + +// Builds upon wagiminator by Stefan Wagner +// Github: https://github.com/wagiminator +// License: http://creativecommons.org/licenses/by-sa/3.0/ + +#include +#include +#include +#include +#include +#include +#include + +#define I2C_BUS "/dev/i2c-1" + +// Example bitmap: 128x64 monochrome pattern +unsigned char splash_bmp[1024] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x70, 0xe0, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xfe, 0xfe, 0x67, 0x63, 0x63, 0x63, 0x67, 0x7e, + 0x7c, 0x20, 0x00, 0x00, 0xff, 0xff, 0x06, 0x03, 0x03, 0x03, 0x03, 0xff, 0xfe, 0xfe, 0x07, 0x03, + 0x03, 0x03, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0xfe, 0xfe, 0x07, 0x03, 0x03, 0x03, 0x03, + 0x0f, 0xfe, 0xfc, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0e, 0x03, 0x03, 0x03, 0x03, 0x0f, 0xfe, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x1f, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x48, 0x48, 0xf8, 0xb0, 0x80, 0xe0, 0x20, + 0x20, 0xe0, 0x80, 0x80, 0xe0, 0x20, 0x20, 0xe0, 0x80, 0x20, 0xf8, 0x20, 0x20, 0x00, 0xe8, 0x00, + 0x00, 0xe0, 0x20, 0x20, 0xe0, 0xc0, 0x80, 0xe0, 0x20, 0x20, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x06, 0x03, 0x01, 0x07, 0x04, + 0x04, 0x07, 0x01, 0x01, 0x07, 0x04, 0x04, 0x07, 0x01, 0x00, 0x07, 0x04, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x07, 0x07, 0x01, 0x27, 0x24, 0x24, 0x3f, 0x0f, 0x00, 0x04, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +#define OLED_ADDR 0x3C // OLED 7-bit address +#define OLED_CMD_MODE 0x00 // set command mode +#define OLED_DAT_MODE 0x40 // set data mode + +#define OLED_MULTIPLEX 0xA8 // set multiplex ratio (following byte) +#define OLED_CHARGEPUMP 0x8D // (following byte - 0x14:enable, 0x10: disable) +#define OLED_MEMORYMODE 0x20 // set memory addressing mode (following byte) +#define OLED_COLUMNS 0x21 // set start and end column (following 2 bytes) +#define OLED_PAGES 0x22 // set start and end page (following 2 bytes) +#define OLED_COMPINS 0xDA // set COM pin config (following byte) +#define OLED_XFLIP 0xA1 // flip display horizontally +#define OLED_YFLIP 0xC8 // flip display vertically +#define OLED_DISPLAY_ON 0xAF // set display on + +#define OLED_PAGE 0xB0 // set start page (following byte) +#define OLED_COLUMN_HIGH 0x10 // set higher 4 bits of start column (0x10 - 0x1F) + +// Global I2C file descriptor +int i2c_fd; + +// OLED initialisation sequence +const uint8_t OLED_INIT_CMD[] = { + OLED_MULTIPLEX, 0x3F, // set multiplex ratio + OLED_CHARGEPUMP, 0x14, // set DC-DC enable + OLED_MEMORYMODE, 0x02, // set page addressing mode (0x00 = horizontal, 0x02 = page) + OLED_COLUMNS, 0x00, 0x7F, // set start and end column + OLED_PAGES, 0x00, 0x07, // set start and end page (0-7 for 64 pixel height) + OLED_COMPINS, 0x12, // set com pins + OLED_XFLIP, OLED_YFLIP, // flip screen + OLED_DISPLAY_ON // display on +}; + +// I2C write function +int i2c_write_data(uint8_t *data, int length) { + if (write(i2c_fd, data, length) != length) { + perror("Failed to write to I2C device"); + return -1; + } + return 0; +} + +// OLED init function +int OLED_init(void) { + uint8_t cmd_buffer[32]; + int cmd_len = 0; + + // Build command buffer + cmd_buffer[cmd_len++] = OLED_CMD_MODE; + for(int i = 0; i < sizeof(OLED_INIT_CMD); i++) { + cmd_buffer[cmd_len++] = OLED_INIT_CMD[i]; + } + + // Send initialization commands + return i2c_write_data(cmd_buffer, cmd_len); +} + +// OLED set cursor position +int OLED_setpos(uint8_t x, uint8_t y) { + uint8_t cmd_buffer[5]; + cmd_buffer[0] = OLED_CMD_MODE; + cmd_buffer[1] = OLED_PAGE | y; // set page start address + cmd_buffer[2] = x & 0x0F; // set lower nibble of start column + cmd_buffer[3] = OLED_COLUMN_HIGH | (x >> 4); // set higher nibble of start column + + return i2c_write_data(cmd_buffer, 4); +} + +// OLED clear screen +int OLED_clear(void) { + for(uint8_t page = 0; page < 8; page++) { + if (OLED_setpos(0, page) < 0) return -1; + + uint8_t data_buffer[129]; + data_buffer[0] = OLED_DAT_MODE; + memset(&data_buffer[1], 0x00, 128); // Clear all pixels in this page + + if (i2c_write_data(data_buffer, 129) < 0) return -1; + } + return 0; +} + +// OLED draw bitmap +int OLED_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t* bmp) { + const uint8_t* bmp_ptr = bmp; + + for(uint8_t page = y0; page < y1; page++) { + if (OLED_setpos(x0, page) < 0) return -1; + + uint8_t data_buffer[129]; + data_buffer[0] = OLED_DAT_MODE; + + for(uint8_t x = x0; x < x1; x++) { + data_buffer[x - x0 + 1] = *bmp_ptr++; + } + + if (i2c_write_data(data_buffer, (x1 - x0) + 1) < 0) return -1; + } + return 0; +} + +int main() { + // Open I2C bus + i2c_fd = open(I2C_BUS, O_RDWR); + if (i2c_fd < 0) { + perror("Failed to open I2C bus"); + return 1; + } + + // Set I2C slave address + if (ioctl(i2c_fd, I2C_SLAVE, OLED_ADDR) < 0) { + perror("Failed to connect to OLED"); + close(i2c_fd); + return 1; + } + + printf("Initializing OLED...\n"); + + // Initialize OLED + if (OLED_init() < 0) { + printf("Failed to initialize OLED\n"); + close(i2c_fd); + return 1; + } + + printf("Clearing display...\n"); + + // Clear the display first + if (OLED_clear() < 0) { + printf("Failed to clear OLED\n"); + close(i2c_fd); + return 1; + } + + printf("Drawing splash screen...\n"); + + // Draw bitmap splash screen (128x64 pixels = 8 pages) + if (OLED_draw_bmp(0, 0, 128, 8, splash_bmp) < 0) { + printf("Failed to draw splash screen\n"); + close(i2c_fd); + return 1; + } + + printf("Splash screen displayed successfully!\n"); + + close(i2c_fd); + return 0; +} \ No newline at end of file diff --git a/initramfs_splash/oled_display b/initramfs_splash/oled_display new file mode 100644 index 0000000..850aed4 --- /dev/null +++ b/initramfs_splash/oled_display @@ -0,0 +1,15 @@ +#!/bin/sh + +PREREQ="" +prereqs() { echo "$PREREQ"; } + +case "$1" in + prereqs) prereqs; exit 0 ;; +esac + +. /usr/share/initramfs-tools/hook-functions + +echo "Including OLED boot binary in initramfs..." + +# Copy the binary into initramfs +copy_exec /usr/local/bin/oled_boot /usr/local/bin/oled_boot From ccfaeec43ebd70c7f06a974ec86db32768ee7290 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Tue, 27 May 2025 15:49:31 +0100 Subject: [PATCH 5/6] update excutable --- initramfs_splash/install.sh | 0 initramfs_splash/oled | 0 initramfs_splash/oled_display | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 initramfs_splash/install.sh mode change 100644 => 100755 initramfs_splash/oled mode change 100644 => 100755 initramfs_splash/oled_display diff --git a/initramfs_splash/install.sh b/initramfs_splash/install.sh old mode 100644 new mode 100755 diff --git a/initramfs_splash/oled b/initramfs_splash/oled old mode 100644 new mode 100755 diff --git a/initramfs_splash/oled_display b/initramfs_splash/oled_display old mode 100644 new mode 100755 From 01054a1ce363ca3a24cc8491281d1bd32269a1fb Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Thu, 3 Jul 2025 15:20:28 +0100 Subject: [PATCH 6/6] remove deprecated charset --- emonPiLCD1.py | 2 +- emonPiLCD2.py | 2 +- module.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/emonPiLCD1.py b/emonPiLCD1.py index c8ac749..b7b86b6 100755 --- a/emonPiLCD1.py +++ b/emonPiLCD1.py @@ -54,7 +54,7 @@ # ------------------------------------------------------------------------------------ redis_host = config.get('redis', 'redis_host') redis_port = config.get('redis', 'redis_port') -r = redis.Redis(host=redis_host, port=redis_port, db=0, charset="utf-8", decode_responses=True) +r = redis.Redis(host=redis_host, port=redis_port, db=0, decode_responses=True) # ------------------------------------------------------------------------------------ # General Settings diff --git a/emonPiLCD2.py b/emonPiLCD2.py index e0defb2..f7c221e 100755 --- a/emonPiLCD2.py +++ b/emonPiLCD2.py @@ -59,7 +59,7 @@ # ------------------------------------------------------------------------------------ redis_host = config.get('redis', 'redis_host') redis_port = config.get('redis', 'redis_port') -r = redis.Redis(host=redis_host, port=redis_port, db=0, charset="utf-8", decode_responses=True) +r = redis.Redis(host=redis_host, port=redis_port, db=0, decode_responses=True) # ------------------------------------------------------------------------------------ # General Settings diff --git a/module.json b/module.json index 137d920..6098fdf 100644 --- a/module.json +++ b/module.json @@ -1,6 +1,6 @@ { "name" : "emonPiLCD", - "version" : "2.1.0", + "version" : "2.1.1", "location" : "/opt/openenergymonitor", "branches_available": ["stable","master"], "requires": []