Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Kulshrest Tiwari
Published © GPL3+

LoRa chat

Chat application based on pico and LoRa

BeginnerProtip2 hours162
LoRa chat

Things used in this project

Hardware components

SB Components MessengerPi
×1

Software apps and online services

Thonny

Story

Read more

Code

MessengerPi.py

Python
liberary
from machine import Pin,SPI
import machine
import utime
import st7789
import time

# key mappings 
keys_capital = (
        ( "Q", "W", "E", "R", "T","Y" ), 
        ( "U", "I", "O", "P","K", "J" ),
        ( "H", "G", "F","D", "S", "A" ),
        ( "V","B", "N", "M", "BKS", "L" ),
        ( "C", "X", "Z","SHIFT","CTRL"," " ),
        ( "UP","EXT","ENTER","LEFT","RIGHT","DOWN"))

keys_small = (
        ( "q", "w", "e", "r", "t","y" ), 
        ( "u", "i", "o", "p","k", "j" ),
        ( "h", "g", "f","d", "s", "a" ),
        ( "v","b", "n", "m", "bks", "l" ),
        ( "c", "x", "z","shift","ctrl"," " ),
        ( "up","ext","enter","left","right","down"))


keys_num_special = (
        ( "1", "2", "3", "4", "5","6" ), 
        ( "7", "8", "9", "0","-", ")" ),
        ( "(", "&", "%","#", "@", "!" ),
        ( "'",".", ",", "=", "bks", "+" ),
        ( "?", "/", "esc","shift","ctrl"," " ),
        ( "up","ext","enter","right","left","down"))

# define and configure pins as OUTPUT, INPUT
colPins = [23,2,3,20,21,14]  # GPIOs pin used for Column
rowPins = [6,9,15,8,7,22]	 # GPIOs pin used for Row

row = []    # list to hold row pin define
column = [] # list to hold row pin define

for item in rowPins:
    row.append(machine.Pin(item,machine.Pin.OUT))
for item in colPins:
    column.append(machine.Pin(item,machine.Pin.IN,machine.Pin.PULL_DOWN))

rlen = 6
clen = 6

def keyboard(keys_):
    global key
    for rowKey in range(rlen):
        row[rowKey].value(1)
        for colKey in range(clen):
            if column[colKey].value() == 1:
                key = keys_[rowKey][colKey]
                row[rowKey].value(0)
                time.sleep(0.2)
                return(key)
        row[rowKey].value(0)

main.py

Python
apllication code
from machine import Pin, SPI, UART  # Import necessary modules for hardware control
from time import sleep  # Import sleep for delays
import st7789  # Import library for ST7789 TFT display
import MessengerPi  # Import custom module for Messenger functionalities
from MessengerPi import *  # Import all functions from MessengerPi
import vga1_16x32 as font1  # Import a font for larger text
import vga1_8x16 as font  # Import a font for smaller text

# Initialize the SPI interface for the TFT display
spi = SPI(1, baudrate=40000000, sck=Pin(10), mosi=Pin(11))

# Configure the ST7789 TFT display
tft = st7789.ST7789(
    spi, 
    width=320,  # Screen width in pixels
    height=240,  # Screen height in pixels
    cs=Pin(13, Pin.OUT),  # Chip select pin
    dc=Pin(24, Pin.OUT),  # Data/command pin
    backlight=Pin(26, Pin.OUT),  # Backlight control pin
    reset=Pin(12, Pin.OUT)  # Reset pin
)
tft.init()
tft.fill(0)  # Clear the screen (fill with black)

# Function to set up the main interface layout
def front_view():
    tft.fill(st7789.WHITE)  # Fill the screen with white
    # Draw the green button and text area borders
    tft.fill_rect(0, 195, 230, 3, st7789.GREEN)  # Top horizontal line of input box
    tft.fill_rect(230, 195, 3, 45, st7789.GREEN)  # Right vertical line of input box
    tft.fill_rect(0, 237, 230, 3, st7789.GREEN)  # Bottom horizontal line of input box
    tft.fill_rect(0, 195, 3, 45, st7789.GREEN)  # Left vertical line of input box
    tft.fill_rect(215, 195, 105, 45, st7789.GREEN)  # "Send" button background
    tft.text(font1, "Send", 240, 200, st7789.BLUE, st7789.GREEN)  # "Send" button label

# Function to draw a blinking cursor at the given position
def cursor(num, y):
    tft.fill_rect(num + 8, y, 3, 14, st7789.BLACK)  # Draw the cursor

# Function to display messages on the screen
def printing(storage):
    z = 0  # Vertical offset for messages
    tft.fill_rect(0, 0, 320, 195, st7789.WHITE)  # Clear the message display area
    # Display messages from storage (most recent at the bottom)
    for datq in reversed(storage):
        if datq[1] == 0:  # Message sent by the user
            beta = datq[0]
            if "\n" in beta:  # If message contains a newline, split it into lines
                tft.text(font, beta[:beta.find("\n") + 1], 300 - (len(beta[:beta.find("\n") + 1]) * 7), 155 - z, st7789.BLACK, st7789.YELLOW)
                tft.text(font, beta[beta.find("\n") + 1:], 300 - (len(beta[:beta.find("\n") + 1]) * 7), 170 - z, st7789.BLACK, st7789.YELLOW)
                z += 30  # Adjust offset for multi-line messages
            else:
                tft.text(font, datq[0], 300 - (len(datq[0]) * 7), 170 - z, st7789.BLACK, st7789.YELLOW)
                z += 20
        if datq[1] == 1:  # Message received from LoRa
            tft.text(font, datq[0], 5, 170 - z, st7789.BLACK, st7789.CYAN)
            z += 20

# Initialize keyboard layouts and variables
keys = [keys_capital, keys_small, keys_num_special]  # Keyboard layers (capital, small, special characters)
data = ""  # To store the user's current input
num = 5  # Initial x-coordinate for input cursor
extra_word = ["ENTER", "SHIFT", "shift", "enter", "BKS", "bks"]  # Special keys
key_i = 0  # Keyboard layer index
y = 200  # Initial y-coordinate for input cursor
z = 0  # Placeholder for additional vertical offsets
cycle = 0  # Counter for message cycles

storage = []  # To store sent and received messages
front_view()  # Display the main interface
lora_uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))  # Configure UART for LoRa communication

# Main loop
while True:
    key = MessengerPi.keyboard(keys[key_i])  # Get a key press from the keyboard
    
    if key == "SHIFT" or key == "shift":  # Toggle keyboard layer
        key_i = (key_i + 1) % 3  # Switch between capital, small, and special character layouts
        key = MessengerPi.keyboard(keys[key_i])  # Update the key
    
    data_read = lora_uart.readline()  # Read data from LoRa module
    if data_read is not None:
        print(data_read)  # Print received data to console
        storage.append([data_read, 1])  # Add received message to storage
        printing(storage)  # Update the message display

    if key == "ENTER" or key == "enter":  # Send the message when "Enter" is pressed
        sending = data.replace("\n", "")  # Prepare the message for sending
        lora_uart.write(sending)  # Send the message via LoRa
        print(sending)  # Debug: Print the message being sent
        # Highlight the "Send" button momentarily
        tft.fill_rect(215, 195, 105, 45, st7789.YELLOW)
        tft.text(font1, "Send", 240, 200, st7789.BLUE, st7789.YELLOW)
        sleep(0.2)
        tft.fill_rect(215, 195, 105, 45, st7789.GREEN)
        tft.text(font1, "Send", 240, 200, st7789.BLUE, st7789.GREEN)
        # Clear the input area
        tft.fill_rect(num, y, 3, 14, st7789.WHITE)
        # Reset variables and update storage
        storage.append([data, 0])  # Add sent message to storage
        data = ""  # Clear current input
        printing(storage)  # Refresh message display
    
    # Update input area based on key press
    if key is not None and key not in extra_word:
        data += key  # Append key to current input
        tft.text(font, key, num, y, st7789.BLACK, st7789.WHITE)  # Display the key
        cursor(num, y)  # Update cursor
        num += 8  # Move cursor forward

    if key == " ":
        tft.fill_rect(num, y, 4, 14, st7789.WHITE)  # Add space
        cursor(num, y)
        data += key
        num += 8

    if key == "bks" or key == "BKS":  # Handle backspace
        tft.text(font, data[-1:], num - 8, y, st7789.WHITE, st7789.WHITE)  # Erase last character
        num -= 8  # Move cursor back
        cursor(num - 8, y)
        data = data[:-1]  # Remove last character from input

    if num > 205:  # Handle line wrap
        tft.fill_rect(num, y, 3, 14, st7789.WHITE)  # Clear cursor
        data += "\n"  # Add newline to input
        y = 220  # Move to next line
        num = 5  # Reset x-coordinate
    
    sleep(0.05)  # Small delay to prevent input flooding

Credits

Kulshrest Tiwari
5 projects • 2 followers
embedded sofware engineer
Contact

Comments

Please log in or sign up to comment.