first save
This commit is contained in:
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
0
app/classes/__init__.py
Normal file
0
app/classes/__init__.py
Normal file
9
app/classes/location.py
Normal file
9
app/classes/location.py
Normal file
@@ -0,0 +1,9 @@
|
||||
class Location:
|
||||
def __init__(self, **kwargs):
|
||||
self.name = kwargs.get('name', '')
|
||||
self.region = kwargs.get('region', '')
|
||||
self.country = kwargs.get('country', '')
|
||||
self.localtime = kwargs.get('localtime', '')
|
||||
|
||||
def __repr__(self):
|
||||
return f"Location(name='{self.name}', region='{self.region}', country='{self.country}')"
|
||||
59
app/classes/weather.py
Normal file
59
app/classes/weather.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from .location import Location
|
||||
|
||||
|
||||
class Condition:
|
||||
def __init__(self, **kwargs):
|
||||
self.text = kwargs.get('text')
|
||||
self.icon = kwargs.get('icon')
|
||||
|
||||
def __repr__(self):
|
||||
return f'Condition(text={self.text}, icon={self.icon})'
|
||||
|
||||
|
||||
class AirQuality:
|
||||
def __init__(self, **kwargs):
|
||||
# Required pollutants
|
||||
self.co = float(kwargs.get('co', 0))
|
||||
self.no2 = float(kwargs.get('no2', 0))
|
||||
self.o3 = float(kwargs.get('o3', 0))
|
||||
self.so2 = float(kwargs.get('so2', 0))
|
||||
self.pm2_5 = float(kwargs.get('pm2_5'))
|
||||
self.pm10 = float(kwargs.get('pm10', 0))
|
||||
# Air quality indices
|
||||
self.us_epa_index = int(kwargs.get('us-epa-index', 0))
|
||||
self.gb_defra_index = int(kwargs.get('gb-defra-index', 0))
|
||||
|
||||
def __repr__(self):
|
||||
return f'AirQuality(CO={self.co}, NO2={self.no2}, O3={self.o3}, PM2.5={self.pm2_5})'
|
||||
|
||||
|
||||
class CurrentCondition:
|
||||
def __init__(
|
||||
self,
|
||||
# condition,
|
||||
# air_quality,
|
||||
**kwargs,
|
||||
):
|
||||
self.last_updated = kwargs.get('last_updated', '')
|
||||
self.temp_c = float(kwargs.get('temp_c', 0))
|
||||
self.is_day = int(kwargs.get('is_day', 0))
|
||||
self.condition = Condition(**kwargs.get('condition'))
|
||||
self.wind_kph = float(kwargs.get('wind_kph', 0))
|
||||
self.wind_dir = kwargs.get('wind_dir', '')
|
||||
self.pressure_mb = float(kwargs.get('pressure_mb', 0))
|
||||
self.humidity = int(kwargs.get('humidity', 0))
|
||||
self.cloud = int(kwargs.get('cloud', 0))
|
||||
self.feelslike_c = float(kwargs.get('feelslike_c', 0))
|
||||
self.air_quality = AirQuality(**kwargs.get('air_quality'))
|
||||
|
||||
def __repr__(self):
|
||||
return f'CurrentCondition(condition={self.condition}, air_quality={self.air_quality}, last_updated={self.last_updated}, temp_c={self.temp_c}, wind_dir={self.wind_dir}, wind_kph={self.wind_kph})'
|
||||
|
||||
|
||||
class Weather:
|
||||
def __init__(self, location, current):
|
||||
self.location = location
|
||||
self.current = current
|
||||
|
||||
def __repr__(self):
|
||||
return f'Weather(condition={self.location}, current={self.current}'
|
||||
0
app/display/__init__.py
Normal file
0
app/display/__init__.py
Normal file
337
app/display/emoji/emoji_16x16.py
Normal file
337
app/display/emoji/emoji_16x16.py
Normal file
@@ -0,0 +1,337 @@
|
||||
# Emoji symbols for LED matrix (16x16)
|
||||
emoji_16x16 = {
|
||||
# Basic Smileys
|
||||
'😀': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0xFFFF,
|
||||
0xFFFF,
|
||||
0xFFFF,
|
||||
0xFFFF,
|
||||
0xFFFF,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
0x0000,
|
||||
], # Grinning face (circle outline)
|
||||
'😊': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7C3E,
|
||||
0xF81F,
|
||||
0xF00F,
|
||||
0xF00F,
|
||||
0xF00F,
|
||||
0xF00F,
|
||||
0xF81F,
|
||||
0x7C3E,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
], # Smiling face
|
||||
'😂': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7C3E,
|
||||
0xF99F,
|
||||
0xF3CF,
|
||||
0xF3CF,
|
||||
0xF3CF,
|
||||
0xF3CF,
|
||||
0xF99F,
|
||||
0x7C3E,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
], # Laughing with tears
|
||||
'😍': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7C3E,
|
||||
0xF81F,
|
||||
0xF3CF,
|
||||
0xE7E7,
|
||||
0xE7E7,
|
||||
0xF3CF,
|
||||
0xF81F,
|
||||
0x7C3E,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
], # Heart eyes
|
||||
'😎': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0xFFFF,
|
||||
0xF00F,
|
||||
0xF00F,
|
||||
0xF00F,
|
||||
0xF00F,
|
||||
0xFFFF,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
], # Cool sunglasses
|
||||
# Hearts
|
||||
'❤️': [
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x0C30,
|
||||
0x1E78,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0xFFFE,
|
||||
0xFFFC,
|
||||
0x7FF8,
|
||||
0x7FF0,
|
||||
0x3FE0,
|
||||
0x1FC0,
|
||||
0x0F80,
|
||||
0x0700,
|
||||
0x0000,
|
||||
], # Red heart
|
||||
# Weather & Nature
|
||||
'☀️': [
|
||||
0x8001,
|
||||
0x4002,
|
||||
0x2004,
|
||||
0x1188,
|
||||
0x0DB0,
|
||||
0x07E0,
|
||||
0x03C0,
|
||||
0xFFFF,
|
||||
0xFFFF,
|
||||
0x03C0,
|
||||
0x07E0,
|
||||
0x0DB0,
|
||||
0x1188,
|
||||
0x2004,
|
||||
0x4002,
|
||||
0x8001,
|
||||
], # Sun with detailed rays
|
||||
'🌙': [
|
||||
0x0000,
|
||||
0x1F80,
|
||||
0x3FC0,
|
||||
0x7FE0,
|
||||
0xFFF0,
|
||||
0xFFF8,
|
||||
0xFFF8,
|
||||
0xFFF0,
|
||||
0xFFE0,
|
||||
0xFFC0,
|
||||
0xFF80,
|
||||
0xFF00,
|
||||
0xFE00,
|
||||
0xFC00,
|
||||
0xF800,
|
||||
0x0000,
|
||||
], # Crescent moon
|
||||
'⭐': [
|
||||
0x0180,
|
||||
0x0180,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
0x07E0,
|
||||
0x0FF0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x0FF0,
|
||||
0x07E0,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
0x0180,
|
||||
0x0180,
|
||||
], # Star
|
||||
# Objects
|
||||
'📱': [
|
||||
0xFFFF,
|
||||
0x8001,
|
||||
0x8001,
|
||||
0x9FF9,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9009,
|
||||
0x9FF9,
|
||||
0x8001,
|
||||
0x8001,
|
||||
0xFFFF,
|
||||
], # Smartphone
|
||||
'💻': [
|
||||
0x0000,
|
||||
0x7FFE,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x4002,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x0000,
|
||||
], # Laptop
|
||||
# Animals
|
||||
'🐱': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
0x0000,
|
||||
], # Cat face
|
||||
'🐶': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x6FF6,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
0x0000,
|
||||
], # Dog face
|
||||
# Food
|
||||
'🍕': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
0x0000,
|
||||
], # Pizza
|
||||
# Technology
|
||||
'🔒': [
|
||||
0x0FC0,
|
||||
0x1FE0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
], # Lock
|
||||
# Vehicles
|
||||
'🚗': [
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x0FC0,
|
||||
0x1FE0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x3FF0,
|
||||
0x1FE0,
|
||||
0x0FC0,
|
||||
0x0000,
|
||||
0x0000,
|
||||
], # Car
|
||||
# Sports
|
||||
'⚽': [
|
||||
0x07E0,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x7FFE,
|
||||
0x3FFC,
|
||||
0x1FF8,
|
||||
0x07E0,
|
||||
0x0000,
|
||||
], # Soccer ball
|
||||
# Holidays
|
||||
'🎄': [
|
||||
0x0180,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
0x07E0,
|
||||
0x07E0,
|
||||
0x0FF0,
|
||||
0x0FF0,
|
||||
0x1FF8,
|
||||
0x1FF8,
|
||||
0x3FFC,
|
||||
0x3FFC,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
0x03C0,
|
||||
], # Christmas tree
|
||||
}
|
||||
81
app/display/emoji/emoji_5x7.py
Normal file
81
app/display/emoji/emoji_5x7.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# Emoji symbols for LED matrix (5x7)
|
||||
emoji_5x7 = {
|
||||
# Basic Smileys
|
||||
'😀': [0x0A, 0x00, 0x11, 0x11, 0x00, 0x11, 0x0E], # Grinning face
|
||||
'😊': [0x0A, 0x00, 0x11, 0x11, 0x00, 0x0A, 0x04], # Smiling face
|
||||
'😂': [0x0A, 0x00, 0x1F, 0x11, 0x00, 0x0A, 0x04], # Laughing with tears
|
||||
'😍': [0x0A, 0x00, 0x15, 0x0E, 0x04, 0x0A, 0x11], # Heart eyes
|
||||
'😎': [0x0A, 0x00, 0x11, 0x11, 0x0E, 0x1F, 0x00], # Cool sunglasses
|
||||
'😢': [0x0A, 0x00, 0x11, 0x11, 0x00, 0x0A, 0x04], # Crying face
|
||||
'😠': [0x0A, 0x00, 0x11, 0x11, 0x00, 0x15, 0x0A], # Angry face
|
||||
'😴': [0x0A, 0x00, 0x11, 0x11, 0x00, 0x0E, 0x1F], # Sleeping face
|
||||
# Hearts
|
||||
'❤️': [0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00], # Red heart
|
||||
'💙': [0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00], # Blue heart
|
||||
'💚': [0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00], # Green heart
|
||||
'💛': [0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00], # Yellow heart
|
||||
'💜': [0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00], # Purple heart
|
||||
# Hands & Gestures
|
||||
'👍': [0x04, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04], # Thumbs up
|
||||
'👎': [0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04], # Thumbs down
|
||||
'👏': [0x00, 0x15, 0x15, 0x15, 0x15, 0x0A, 0x0A], # Clapping hands
|
||||
'🙌': [0x11, 0x0A, 0x04, 0x04, 0x04, 0x0A, 0x11], # Raising hands
|
||||
# Common Symbols
|
||||
'⭐': [0x04, 0x04, 0x1F, 0x0E, 0x1F, 0x04, 0x04], # Star
|
||||
'🌟': [0x04, 0x15, 0x0E, 0x1F, 0x0E, 0x15, 0x04], # Glowing star
|
||||
'🎉': [0x04, 0x1F, 0x04, 0x1F, 0x04, 0x0A, 0x11], # Party popper
|
||||
'🎂': [0x0E, 0x11, 0x1F, 0x1F, 0x1F, 0x0A, 0x1F], # Birthday cake
|
||||
# Weather & Nature
|
||||
'☀️': [0x11, 0x0A, 0x1F, 0x0E, 0x1F, 0x0A, 0x11], # Sun
|
||||
'🌙': [0x0C, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00], # Crescent moon
|
||||
'☁️': [0x00, 0x0E, 0x1F, 0x1F, 0x1F, 0x00, 0x00], # Cloud
|
||||
'🌧️': [0x0E, 0x1F, 0x1F, 0x0A, 0x04, 0x0A, 0x04], # Cloud with rain
|
||||
'⚡': [0x04, 0x04, 0x06, 0x1C, 0x04, 0x04, 0x04], # Lightning
|
||||
'❄️': [0x0A, 0x1F, 0x0A, 0x04, 0x0A, 0x1F, 0x0A], # Snowflake
|
||||
# Objects
|
||||
'📱': [0x1F, 0x11, 0x15, 0x15, 0x15, 0x11, 0x1F], # Mobile phone
|
||||
'💻': [0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F], # Laptop
|
||||
'⌚': [0x0E, 0x11, 0x15, 0x15, 0x15, 0x11, 0x0E], # Watch
|
||||
'🔑': [0x04, 0x0E, 0x04, 0x0E, 0x15, 0x15, 0x0E], # Key
|
||||
# Arrows
|
||||
'⬆️': [0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04], # Up arrow
|
||||
'⬇️': [0x04, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04], # Down arrow
|
||||
'⬅️': [0x04, 0x08, 0x1F, 0x08, 0x04, 0x00, 0x00], # Left arrow
|
||||
'➡️': [0x04, 0x02, 0x1F, 0x02, 0x04, 0x00, 0x00], # Right arrow
|
||||
# Status Indicators
|
||||
'✅': [0x00, 0x01, 0x02, 0x14, 0x08, 0x00, 0x00], # Check mark button
|
||||
'❌': [0x11, 0x0A, 0x04, 0x0A, 0x11, 0x00, 0x00], # Cross mark
|
||||
'⚠️': [0x04, 0x04, 0x04, 0x15, 0x0E, 0x04, 0x04], # Warning
|
||||
'🚨': [0x04, 0x0E, 0x1F, 0x04, 0x1F, 0x04, 0x04], # Alarm
|
||||
# Food & Drink
|
||||
'🍕': [0x0E, 0x1F, 0x1F, 0x15, 0x1F, 0x1F, 0x0E], # Pizza
|
||||
'🍎': [0x04, 0x0A, 0x11, 0x1F, 0x1F, 0x0E, 0x04], # Apple
|
||||
'☕': [0x0E, 0x11, 0x1F, 0x11, 0x0E, 0x04, 0x04], # Coffee
|
||||
# Animals
|
||||
'🐱': [0x0E, 0x0A, 0x0E, 0x1F, 0x15, 0x11, 0x0A], # Cat face
|
||||
'🐶': [0x0E, 0x0A, 0x0E, 0x1F, 0x15, 0x15, 0x0A], # Dog face
|
||||
'🐭': [0x0C, 0x12, 0x0C, 0x1E, 0x0B, 0x0B, 0x06], # Mouse face
|
||||
# Holidays
|
||||
'🎄': [0x04, 0x04, 0x0E, 0x0E, 0x1F, 0x04, 0x04], # Christmas tree
|
||||
'🎃': [0x0E, 0x15, 0x1F, 0x1B, 0x1F, 0x15, 0x0E], # Jack-o-lantern
|
||||
'🎅': [0x04, 0x0E, 0x04, 0x0E, 0x1F, 0x0A, 0x04], # Santa Claus
|
||||
# Technology
|
||||
'🔒': [0x0E, 0x11, 0x11, 0x1F, 0x1B, 0x1B, 0x1F], # Locked
|
||||
'🔓': [0x0E, 0x10, 0x10, 0x1F, 0x1B, 0x1B, 0x1F], # Unlocked
|
||||
'🔋': [0x1F, 0x11, 0x15, 0x15, 0x15, 0x11, 0x1F], # Battery
|
||||
'🔍': [0x00, 0x0E, 0x01, 0x0D, 0x15, 0x15, 0x0D], # Magnifying glass
|
||||
# Music
|
||||
'🎵': [0x02, 0x03, 0x02, 0x0E, 0x1E, 0x0C, 0x00], # Music note
|
||||
'🎶': [0x0A, 0x0A, 0x0A, 0x0A, 0x0E, 0x0E, 0x04], # Multiple music notes
|
||||
# Sports
|
||||
'⚽': [0x0E, 0x11, 0x15, 0x15, 0x15, 0x11, 0x0E], # Soccer ball
|
||||
'🏀': [0x0E, 0x11, 0x17, 0x15, 0x17, 0x11, 0x0E], # Basketball
|
||||
# Time
|
||||
'🕐': [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E], # One o'clock
|
||||
'🕒': [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E], # Three o'clock
|
||||
'🕔': [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E], # Five o'clock
|
||||
# Miscellaneous
|
||||
'💡': [0x04, 0x0A, 0x0A, 0x0A, 0x1F, 0x0E, 0x04], # Light bulb
|
||||
'💰': [0x00, 0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x00], # Money bag
|
||||
'🎁': [0x1F, 0x11, 0x1F, 0x1F, 0x0A, 0x0A, 0x0A], # Wrapped gift
|
||||
}
|
||||
52
app/display/emoji/emoji_8x8.py
Normal file
52
app/display/emoji/emoji_8x8.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# Emoji symbols for LED matrix (8x8)
|
||||
emoji_8x8 = {
|
||||
# Basic Smileys
|
||||
'😀': [0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C], # Grinning face
|
||||
'😊': [0x3C, 0x42, 0xA5, 0x81, 0x81, 0x99, 0x42, 0x3C], # Smiling face
|
||||
'😂': [0x3C, 0x42, 0xA5, 0x89, 0x89, 0x95, 0x42, 0x3C], # Laughing with tears
|
||||
'😍': [0x3C, 0x42, 0xA5, 0x81, 0x99, 0x66, 0x42, 0x3C], # Heart eyes
|
||||
'😎': [0x3C, 0x42, 0xA5, 0x81, 0x81, 0xFF, 0x7E, 0x3C], # Cool sunglasses
|
||||
'😢': [0x3C, 0x42, 0xA5, 0x81, 0x81, 0x99, 0x52, 0x3C], # Crying face
|
||||
'😠': [0x3C, 0x42, 0xA5, 0x81, 0x81, 0x99, 0x5A, 0x3C], # Angry face
|
||||
'😴': [0x3C, 0x42, 0xA5, 0x81, 0x81, 0x81, 0x7E, 0x3C], # Sleeping face
|
||||
# Hearts
|
||||
'💙': [0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Blue heart
|
||||
'💚': [0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Green heart
|
||||
'❤️': [0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Red heart !!! NOT WORKING !!!
|
||||
'💛': [0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Yellow heart
|
||||
# Hands & Gestures
|
||||
'👍': [0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18], # Thumbs up
|
||||
'👎': [0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18], # Thumbs down
|
||||
'👏': [0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18], # Clapping hands
|
||||
# Common Symbols
|
||||
'⭐': [0x18, 0x18, 0x3C, 0xFF, 0xFF, 0x3C, 0x18, 0x18], # Star
|
||||
'🌟': [0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Glowing star
|
||||
'🎉': [0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18], # Party popper
|
||||
# Weather & Nature
|
||||
'☀️': [0x42, 0x81, 0x5A, 0x3C, 0x3C, 0x5A, 0x81, 0x42], # Sun with rays
|
||||
'🌙': [0x3C, 0x42, 0x84, 0x84, 0x84, 0x84, 0x42, 0x3C], # Crescent moon
|
||||
'☁️': [0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x00], # Cloud
|
||||
'🌧️': [0x3C, 0x7E, 0xFF, 0xFF, 0x24, 0x48, 0x24, 0x48], # Cloud with rain
|
||||
'⚡': [0x08, 0x0C, 0x0E, 0xFF, 0x0E, 0x0C, 0x08, 0x00], # Lightning
|
||||
# Objects
|
||||
'📱': [0xFF, 0x81, 0xBD, 0xA5, 0xA5, 0xBD, 0x81, 0xFF], # Mobile phone
|
||||
'💻': [0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF], # Laptop
|
||||
# Arrows
|
||||
'⬆️': [0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18], # Up arrow
|
||||
'⬇️': [0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18], # Down arrow
|
||||
# Status Indicators
|
||||
'✅': [0x00, 0x01, 0x03, 0x16, 0x6C, 0xD8, 0x70, 0x20], # Check mark
|
||||
'❌': [0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81], # Cross mark
|
||||
# Food & Drink
|
||||
'🍕': [0x3C, 0x7E, 0xFF, 0xDB, 0xFF, 0x7E, 0x3C, 0x00], # Pizza
|
||||
'🍎': [0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Apple
|
||||
# Animals
|
||||
'🐱': [0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x5A, 0x3C], # Cat face
|
||||
'🐶': [0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C], # Dog face
|
||||
# Music
|
||||
'🎵': [0x00, 0x03, 0x0F, 0x3F, 0x3F, 0x0F, 0x03, 0x00], # Music note
|
||||
# Sports
|
||||
'⚽': [0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C], # Soccer ball
|
||||
# Miscellaneous
|
||||
'💡': [0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18], # Light bulb
|
||||
}
|
||||
0
app/display/fonts/__init__.py
Normal file
0
app/display/fonts/__init__.py
Normal file
1762
app/display/fonts/font_16x16.py
Normal file
1762
app/display/fonts/font_16x16.py
Normal file
File diff suppressed because it is too large
Load Diff
90
app/display/fonts/font_3x5.py
Normal file
90
app/display/fonts/font_3x5.py
Normal file
@@ -0,0 +1,90 @@
|
||||
font_3x5 = {
|
||||
# Uppercase Letters
|
||||
'A': [0x07, 0x05, 0x07],
|
||||
'B': [0x07, 0x07, 0x07],
|
||||
'C': [0x07, 0x01, 0x07],
|
||||
'D': [0x06, 0x05, 0x06],
|
||||
'E': [0x07, 0x03, 0x07],
|
||||
'F': [0x07, 0x03, 0x01],
|
||||
'G': [0x07, 0x05, 0x07],
|
||||
'H': [0x05, 0x07, 0x05],
|
||||
'I': [0x07, 0x02, 0x07],
|
||||
'J': [0x04, 0x05, 0x07],
|
||||
'K': [0x05, 0x03, 0x05],
|
||||
'L': [0x01, 0x01, 0x07],
|
||||
'M': [0x07, 0x07, 0x05],
|
||||
'N': [0x07, 0x05, 0x05],
|
||||
'O': [0x07, 0x05, 0x07],
|
||||
'P': [0x07, 0x07, 0x01],
|
||||
'Q': [0x07, 0x05, 0x07],
|
||||
'R': [0x07, 0x07, 0x05],
|
||||
'S': [0x07, 0x07, 0x07],
|
||||
'T': [0x07, 0x02, 0x02],
|
||||
'U': [0x05, 0x05, 0x07],
|
||||
'V': [0x05, 0x05, 0x02],
|
||||
'W': [0x05, 0x07, 0x07],
|
||||
'X': [0x05, 0x02, 0x05],
|
||||
'Y': [0x05, 0x07, 0x02],
|
||||
'Z': [0x07, 0x02, 0x07],
|
||||
# Numbers
|
||||
'0': [0x07, 0x05, 0x07],
|
||||
'1': [0x02, 0x02, 0x02],
|
||||
'2': [0x07, 0x07, 0x07],
|
||||
'3': [0x07, 0x07, 0x07],
|
||||
'4': [0x05, 0x07, 0x04],
|
||||
'5': [0x07, 0x07, 0x07],
|
||||
'6': [0x07, 0x07, 0x07],
|
||||
'7': [0x07, 0x04, 0x04],
|
||||
'8': [0x07, 0x07, 0x07],
|
||||
'9': [0x07, 0x07, 0x07],
|
||||
# Lowercase (limited)
|
||||
'a': [0x06, 0x07, 0x07],
|
||||
'b': [0x01, 0x07, 0x07],
|
||||
'c': [0x07, 0x01, 0x07],
|
||||
'd': [0x04, 0x07, 0x07],
|
||||
'e': [0x07, 0x07, 0x03],
|
||||
'f': [0x06, 0x07, 0x02],
|
||||
'g': [0x07, 0x07, 0x06],
|
||||
'h': [0x01, 0x07, 0x05],
|
||||
'i': [0x02, 0x00, 0x02],
|
||||
'j': [0x04, 0x00, 0x06],
|
||||
'k': [0x01, 0x06, 0x05],
|
||||
'l': [0x02, 0x02, 0x02],
|
||||
'm': [0x07, 0x07, 0x05],
|
||||
'n': [0x07, 0x05, 0x05],
|
||||
'o': [0x07, 0x05, 0x07],
|
||||
'p': [0x07, 0x07, 0x01],
|
||||
'q': [0x07, 0x07, 0x04],
|
||||
'r': [0x07, 0x01, 0x01],
|
||||
's': [0x07, 0x07, 0x07],
|
||||
't': [0x02, 0x07, 0x02],
|
||||
'u': [0x05, 0x05, 0x07],
|
||||
'v': [0x05, 0x05, 0x02],
|
||||
'w': [0x05, 0x07, 0x07],
|
||||
'x': [0x05, 0x02, 0x05],
|
||||
'y': [0x05, 0x07, 0x02],
|
||||
'z': [0x07, 0x02, 0x07],
|
||||
# Punctuation
|
||||
' ': [0x00, 0x00, 0x00],
|
||||
'.': [0x00, 0x00, 0x02],
|
||||
',': [0x00, 0x00, 0x02],
|
||||
'!': [0x02, 0x02, 0x00],
|
||||
'?': [0x07, 0x06, 0x02],
|
||||
':': [0x00, 0x02, 0x00],
|
||||
';': [0x00, 0x02, 0x02],
|
||||
'-': [0x00, 0x07, 0x00],
|
||||
'_': [0x00, 0x00, 0x07],
|
||||
'+': [0x02, 0x07, 0x02],
|
||||
'=': [0x07, 0x00, 0x07],
|
||||
'(': [0x02, 0x01, 0x02],
|
||||
')': [0x02, 0x04, 0x02],
|
||||
'[': [0x03, 0x01, 0x03],
|
||||
']': [0x06, 0x04, 0x06],
|
||||
'/': [0x04, 0x02, 0x01],
|
||||
'\\': [0x01, 0x02, 0x04],
|
||||
'*': [0x05, 0x02, 0x05],
|
||||
'"': [0x05, 0x00, 0x00],
|
||||
"'": [0x02, 0x00, 0x00],
|
||||
'°': [0x02, 0x05, 0x02], # Degree symbol
|
||||
'|': [0x02, 0x02, 0x02], # Vertical bar
|
||||
}
|
||||
109
app/display/fonts/font_5x7.py
Normal file
109
app/display/fonts/font_5x7.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# fonts.py - Ready-to-use fonts for LED matrix
|
||||
|
||||
|
||||
# 5x7 Font (Medium)
|
||||
font_5x7 = {
|
||||
# Uppercase letters (A-Z)
|
||||
'A': [0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11],
|
||||
'B': [0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E],
|
||||
'C': [0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E],
|
||||
'D': [0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E],
|
||||
'E': [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F],
|
||||
'F': [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10],
|
||||
'G': [0x0E, 0x11, 0x10, 0x13, 0x11, 0x11, 0x0F],
|
||||
'H': [0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11],
|
||||
'I': [0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E],
|
||||
'J': [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C],
|
||||
'K': [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11],
|
||||
'L': [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F],
|
||||
'M': [0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11],
|
||||
'N': [0x11, 0x19, 0x19, 0x15, 0x13, 0x13, 0x11],
|
||||
'O': [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E],
|
||||
'P': [0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10],
|
||||
'Q': [0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D],
|
||||
'R': [0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11],
|
||||
'S': [0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E],
|
||||
'T': [0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],
|
||||
'U': [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E],
|
||||
'V': [0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04],
|
||||
'W': [0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A],
|
||||
'X': [0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11],
|
||||
'Y': [0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04],
|
||||
'Z': [0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F],
|
||||
# Lowercase letters (a-z)
|
||||
'a': [0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F],
|
||||
'b': [0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x1E],
|
||||
'c': [0x00, 0x00, 0x0E, 0x11, 0x10, 0x11, 0x0E],
|
||||
'd': [0x01, 0x01, 0x0D, 0x13, 0x11, 0x11, 0x0F],
|
||||
'e': [0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E],
|
||||
'f': [0x06, 0x09, 0x08, 0x1C, 0x08, 0x08, 0x08],
|
||||
'g': [0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01, 0x0E],
|
||||
'h': [0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11],
|
||||
'i': [0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E],
|
||||
'j': [0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0C],
|
||||
'k': [0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12],
|
||||
'l': [0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E],
|
||||
'm': [0x00, 0x00, 0x1A, 0x15, 0x15, 0x15, 0x15],
|
||||
'n': [0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11],
|
||||
'o': [0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E],
|
||||
'p': [0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10],
|
||||
'q': [0x00, 0x00, 0x0D, 0x13, 0x0F, 0x01, 0x01],
|
||||
'r': [0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10],
|
||||
's': [0x00, 0x00, 0x0E, 0x10, 0x0E, 0x01, 0x1E],
|
||||
't': [0x08, 0x08, 0x1C, 0x08, 0x08, 0x09, 0x06],
|
||||
'u': [0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D],
|
||||
'v': [0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04],
|
||||
'w': [0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A],
|
||||
'x': [0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11],
|
||||
'y': [0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E],
|
||||
'z': [0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F],
|
||||
# Numbers (0-9)
|
||||
'0': [0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E],
|
||||
'1': [0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E],
|
||||
'2': [0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F],
|
||||
'3': [0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E],
|
||||
'4': [0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02],
|
||||
'5': [0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E],
|
||||
'6': [0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E],
|
||||
'7': [0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08],
|
||||
'8': [0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E],
|
||||
'9': [0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C],
|
||||
# Punctuation and symbols
|
||||
' ': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'!': [0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04],
|
||||
'?': [0x0E, 0x11, 0x02, 0x04, 0x04, 0x00, 0x04],
|
||||
'.': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04],
|
||||
',': [0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08],
|
||||
':': [0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00],
|
||||
';': [0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08],
|
||||
"'": [0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'"': [0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'-': [0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00],
|
||||
'_': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F],
|
||||
'+': [0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00],
|
||||
'=': [0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00],
|
||||
'*': [0x00, 0x0A, 0x04, 0x1F, 0x04, 0x0A, 0x00],
|
||||
'/': [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00],
|
||||
'\\': [0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00],
|
||||
'(': [0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02],
|
||||
')': [0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08],
|
||||
'[': [0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E],
|
||||
']': [0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E],
|
||||
'{': [0x06, 0x04, 0x04, 0x08, 0x04, 0x04, 0x06],
|
||||
'}': [0x0C, 0x04, 0x04, 0x02, 0x04, 0x04, 0x0C],
|
||||
'<': [0x00, 0x01, 0x02, 0x04, 0x02, 0x01, 0x00],
|
||||
'>': [0x00, 0x08, 0x04, 0x02, 0x04, 0x08, 0x00],
|
||||
'@': [0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0E],
|
||||
'#': [0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A],
|
||||
'$': [0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04],
|
||||
'%': [0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03],
|
||||
'&': [0x0C, 0x12, 0x14, 0x08, 0x15, 0x12, 0x0D],
|
||||
'^': [0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00],
|
||||
'~': [0x00, 0x00, 0x00, 0x0D, 0x12, 0x00, 0x00],
|
||||
# Special characters
|
||||
'°': [0x0E, 0x0A, 0x0E, 0x00, 0x00, 0x00, 0x00], # Degree symbol
|
||||
'|': [0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04], # Vertical bar
|
||||
'`': [0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00], # Backtick
|
||||
'¶': [0x1E, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A], # Paragraph symbol
|
||||
'•': [0x00, 0x00, 0x04, 0x0E, 0x04, 0x00, 0x00], # Bullet point
|
||||
}
|
||||
109
app/display/fonts/font_8x8.py
Normal file
109
app/display/fonts/font_8x8.py
Normal file
@@ -0,0 +1,109 @@
|
||||
font_8x8 = {
|
||||
# Uppercase Letters
|
||||
'A': [0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00],
|
||||
'B': [0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00],
|
||||
'C': [0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00],
|
||||
'D': [0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00],
|
||||
'E': [0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00],
|
||||
'F': [0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00],
|
||||
'G': [0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00],
|
||||
'H': [0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00],
|
||||
'I': [0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00],
|
||||
'J': [0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00],
|
||||
'K': [0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00],
|
||||
'L': [0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00],
|
||||
'M': [0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00],
|
||||
'N': [0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00],
|
||||
'O': [0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00],
|
||||
'P': [0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00],
|
||||
'Q': [0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x0E, 0x00],
|
||||
'R': [0x7C, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0x66, 0x00],
|
||||
'S': [0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00],
|
||||
'T': [0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00],
|
||||
'U': [0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00],
|
||||
'V': [0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00],
|
||||
'W': [0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00],
|
||||
'X': [0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00],
|
||||
'Y': [0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00],
|
||||
'Z': [0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00],
|
||||
# Lowercase Letters
|
||||
'a': [0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00],
|
||||
'b': [0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00],
|
||||
'c': [0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00],
|
||||
'd': [0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00],
|
||||
'e': [0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00],
|
||||
'f': [0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x30, 0x00],
|
||||
'g': [0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C],
|
||||
'h': [0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00],
|
||||
'i': [0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00],
|
||||
'j': [0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C],
|
||||
'k': [0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00],
|
||||
'l': [0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00],
|
||||
'm': [0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00],
|
||||
'n': [0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00],
|
||||
'o': [0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00],
|
||||
'p': [0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60],
|
||||
'q': [0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06],
|
||||
'r': [0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00],
|
||||
's': [0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00],
|
||||
't': [0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00],
|
||||
'u': [0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00],
|
||||
'v': [0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00],
|
||||
'w': [0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00],
|
||||
'x': [0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00],
|
||||
'y': [0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78],
|
||||
'z': [0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00],
|
||||
# Numbers
|
||||
'0': [0x3C, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x3C, 0x00],
|
||||
'1': [0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00],
|
||||
'2': [0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00],
|
||||
'3': [0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00],
|
||||
'4': [0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00],
|
||||
'5': [0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00],
|
||||
'6': [0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00],
|
||||
'7': [0x7E, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00],
|
||||
'8': [0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00],
|
||||
'9': [0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00],
|
||||
# Punctuation and Symbols
|
||||
' ': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'!': [0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00],
|
||||
'?': [0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00],
|
||||
'.': [0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00],
|
||||
',': [0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30],
|
||||
':': [0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00],
|
||||
';': [0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30],
|
||||
"'": [0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'"': [0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'-': [0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00],
|
||||
'_': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E],
|
||||
'+': [0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00],
|
||||
'=': [0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00],
|
||||
'*': [0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00],
|
||||
'/': [0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00],
|
||||
'\\': [0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00],
|
||||
'(': [0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00],
|
||||
')': [0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00],
|
||||
'[': [0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00],
|
||||
']': [0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00],
|
||||
'{': [0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00],
|
||||
'}': [0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00],
|
||||
'<': [0x00, 0x06, 0x0C, 0x18, 0x0C, 0x06, 0x00, 0x00],
|
||||
'>': [0x00, 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0x00],
|
||||
'@': [0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x9E, 0x40, 0x3C],
|
||||
'#': [0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00],
|
||||
'$': [0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00],
|
||||
'%': [0x62, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x46, 0x00],
|
||||
'&': [0x3C, 0x66, 0x3C, 0x38, 0x67, 0x66, 0x3F, 0x00],
|
||||
'^': [0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
'~': [0x00, 0x00, 0x00, 0x36, 0x6C, 0x00, 0x00, 0x00],
|
||||
# Special Characters
|
||||
'°': [0x1C, 0x22, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00], # Degree
|
||||
'|': [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00], # Vertical bar
|
||||
'`': [0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # Backtick
|
||||
'¶': [0x3E, 0x7A, 0x7A, 0x7A, 0x3A, 0x0A, 0x0A, 0x00], # Paragraph
|
||||
'•': [0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00], # Bullet
|
||||
'♥': [0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00], # Heart
|
||||
'♦': [0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00], # Diamond
|
||||
'♣': [0x1C, 0x1C, 0x3E, 0x7F, 0x36, 0x1C, 0x3E, 0x00], # Club
|
||||
'♠': [0x1C, 0x3E, 0x7F, 0x7F, 0x1C, 0x1C, 0x3E, 0x00], # Spade
|
||||
}
|
||||
33
app/display/fonts/fonts_utils.py
Normal file
33
app/display/fonts/fonts_utils.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from .font_3x5 import font_3x5
|
||||
from .font_5x7 import font_5x7
|
||||
from .font_8x8 import font_8x8
|
||||
from .font_16x16 import font_16x16
|
||||
from ..emoji.emoji_5x7 import emoji_5x7
|
||||
from ..emoji.emoji_8x8 import emoji_8x8
|
||||
from ..emoji.emoji_16x16 import emoji_16x16
|
||||
|
||||
fonts_meta_ = {
|
||||
3: {'w': 3, 'h': 5},
|
||||
5: {'w': 5, 'h': 7},
|
||||
8: {'w': 8, 'h': 8},
|
||||
16: {'w': 16, 'h': 16},
|
||||
}
|
||||
|
||||
|
||||
def fonts_meta(font):
|
||||
if font == font_3x5:
|
||||
return fonts_meta_[3]
|
||||
elif font == font_5x7:
|
||||
return fonts_meta_[5]
|
||||
elif font == font_8x8:
|
||||
return fonts_meta_[8]
|
||||
elif font == font_16x16:
|
||||
return fonts_meta_[16]
|
||||
elif font == emoji_5x7:
|
||||
return fonts_meta_[5]
|
||||
elif font == emoji_8x8:
|
||||
return fonts_meta_[8]
|
||||
elif font == emoji_16x16:
|
||||
return fonts_meta_[16]
|
||||
else:
|
||||
return None
|
||||
323
app/display/neopixel_64x64.py
Normal file
323
app/display/neopixel_64x64.py
Normal file
@@ -0,0 +1,323 @@
|
||||
from machine import Pin, RTC
|
||||
from neopixel import NeoPixel
|
||||
from .fonts.fonts_utils import fonts_meta
|
||||
from .fonts.font_5x7 import font_5x7
|
||||
from ..utils.colors import RAINBOW, BLACK
|
||||
from ..utils.utils import (
|
||||
get_german_timestamp_short,
|
||||
get_datetime_string,
|
||||
get_german_time_ticks,
|
||||
get_german_date_ticks,
|
||||
)
|
||||
import time
|
||||
import math
|
||||
|
||||
|
||||
class NeoPixel_64x64(NeoPixel):
|
||||
MATRIX_WIDTH = 64
|
||||
MATRIX_HEIGHT = 64
|
||||
|
||||
def __init__(self, pin=28):
|
||||
"""
|
||||
Initialize LED Display
|
||||
|
||||
Args:
|
||||
width: Matrix width in pixels
|
||||
height: Matrix height in pixels
|
||||
pin: NeoPixel data pin
|
||||
"""
|
||||
super().__init__(Pin(pin), self.MATRIX_WIDTH * self.MATRIX_HEIGHT)
|
||||
|
||||
# Font configuration
|
||||
self.set_font(font_5x7)
|
||||
|
||||
def set_font(self, font):
|
||||
"""
|
||||
Set the current font for text rendering
|
||||
|
||||
Args:
|
||||
font: Font dictionary from fonts_array
|
||||
"""
|
||||
self.selected_font = font
|
||||
|
||||
self.selected_font_meta = fonts_meta(font)
|
||||
self.font_width = self.selected_font_meta['w']
|
||||
self.font_height = self.selected_font_meta['h']
|
||||
print(f'Font set: width: {self.font_width}; height: {self.font_height}')
|
||||
|
||||
def set_pixel(self, x, y, color):
|
||||
"""
|
||||
Set a single pixel to the specified color
|
||||
|
||||
Args:
|
||||
x: X coordinate
|
||||
y: Y coordinate
|
||||
color: RGB color tuple
|
||||
"""
|
||||
index = y * self.MATRIX_WIDTH + x
|
||||
if 0 <= x < self.MATRIX_WIDTH and 0 <= y < self.MATRIX_HEIGHT:
|
||||
self[index] = color
|
||||
|
||||
def clear(self):
|
||||
"""Clear the entire display (turn off all pixels)"""
|
||||
for i in range(len(self)):
|
||||
self[i] = BLACK
|
||||
self.write()
|
||||
|
||||
def clear_row(self, row: int, effect: bool = False) -> None:
|
||||
"""
|
||||
|
||||
Clear one row of the display (turn off all pixels)\n
|
||||
PRESUMING: font_5x7\n
|
||||
rows: range(0,3) [row-height: 8 pixels, row-length: MATRIX_WIDTH(64)]\n
|
||||
\n
|
||||
row-0: 0 - 511 (Pixel 0 bis Pixel 8 * MATRIX_WIDTH(64)-1)\n
|
||||
row-1: 512 - 1023\n
|
||||
row-2: 1024 - 1535\n
|
||||
row-3: 1536 - 2047\n
|
||||
etc. ...
|
||||
"""
|
||||
|
||||
start = row * 8 * self.MATRIX_WIDTH
|
||||
ende = start + 8 * self.MATRIX_WIDTH - 1
|
||||
|
||||
print(f'clear row: {row} --> pixels {start} to {ende}')
|
||||
for i in range(start, ende):
|
||||
self[i] = BLACK
|
||||
if effect and i % self.MATRIX_WIDTH == 0:
|
||||
self.write()
|
||||
|
||||
self.write()
|
||||
|
||||
def draw_letter(self, letter, x, y, color):
|
||||
"""
|
||||
Draw a single letter using current font
|
||||
|
||||
Args:
|
||||
letter: Character to draw
|
||||
x: X position
|
||||
y: Y position
|
||||
color: RGB color tuple
|
||||
"""
|
||||
if letter in self.selected_font:
|
||||
char_data = self.selected_font[letter]
|
||||
for row in range(self.font_height):
|
||||
row_data = char_data[row]
|
||||
for col in range(self.font_width):
|
||||
# Check if pixel should be lit (MSB first)
|
||||
if row_data & (1 << ((self.font_width - 1) - col)):
|
||||
self.set_pixel(x + col, y + row, color)
|
||||
else:
|
||||
print(f'oops, letter does not exist in the font -> {letter}')
|
||||
|
||||
def draw_text(self, text, x, y, color=RAINBOW[2], spacing=1):
|
||||
"""
|
||||
Draw text string at specified position
|
||||
|
||||
Args:
|
||||
text: String to display
|
||||
x: Starting X position
|
||||
y: Starting Y position
|
||||
color: RGB color tuple
|
||||
spacing: Pixels between characters
|
||||
"""
|
||||
for idx, char in enumerate(text):
|
||||
char_x = x + (idx * (self.font_width + spacing))
|
||||
self.draw_letter(char, char_x, y, color)
|
||||
|
||||
def show_hello(self):
|
||||
"""Display HELLO with timestamp"""
|
||||
self.clear()
|
||||
|
||||
# Draw HELLO in rainbow colors
|
||||
self.draw_text('HELLO!', 6, 4, RAINBOW[2])
|
||||
|
||||
# Show timestamp
|
||||
datetimestr = get_german_timestamp_short()
|
||||
self.draw_text(datetimestr, 2, 15, RAINBOW[4])
|
||||
|
||||
self.write()
|
||||
|
||||
def vertical_floating_text(
|
||||
self, text, x, color=RAINBOW[0], float_range=3, speed=0.2, duration=10
|
||||
):
|
||||
"""
|
||||
Vertical floating text animation
|
||||
|
||||
Args:
|
||||
text: Text to display
|
||||
x: X position (fixed)
|
||||
color: Text color
|
||||
float_range: How many pixels to float up/down
|
||||
speed: Animation speed
|
||||
duration: How long to run animation in seconds
|
||||
"""
|
||||
start_time = time.time()
|
||||
|
||||
while time.time() - start_time < duration:
|
||||
# Calculate floating offset using sine wave
|
||||
offset = math.sin(time.time() * speed) * float_range
|
||||
current_y = int(self.MATRIX_HEIGHT // 2 + offset - (len(text) * self.font_height) // 2)
|
||||
|
||||
self.clear()
|
||||
|
||||
# Draw each letter vertically
|
||||
for i, char in enumerate(text):
|
||||
char_y = current_y + (i * self.font_height)
|
||||
# Keep text within matrix bounds
|
||||
if 0 <= char_y < self.MATRIX_HEIGHT - self.font_height:
|
||||
self.draw_letter(char, x, char_y, color)
|
||||
|
||||
self.write()
|
||||
time.sleep(0.05)
|
||||
|
||||
def horizontal_floating_text(
|
||||
self, text, y, color=RAINBOW[0], float_range=3, speed=0.2, duration=10
|
||||
):
|
||||
"""
|
||||
Horizontal floating text animation
|
||||
|
||||
Args:
|
||||
text: Text to display
|
||||
y: Y position (fixed)
|
||||
color: Text color
|
||||
float_range: How many pixels to float left/right
|
||||
speed: Animation speed
|
||||
duration: How long to run animation in seconds
|
||||
"""
|
||||
start_time = time.time()
|
||||
text_width = len(text) * (self.font_width + 1)
|
||||
counter = 0
|
||||
|
||||
while time.time() - start_time < duration:
|
||||
# Calculate floating offset using sine wave
|
||||
offset = math.sin(counter) * float_range
|
||||
current_x = int(offset) # to right
|
||||
|
||||
self.clear()
|
||||
|
||||
# Draw text at floating position
|
||||
for i, char in enumerate(text):
|
||||
char_x = current_x + (i * (self.font_width + 1))
|
||||
# Keep text within matrix bounds
|
||||
if 0 <= char_x < self.MATRIX_WIDTH - self.font_width:
|
||||
self.draw_letter(char, char_x, y, color)
|
||||
|
||||
self.write()
|
||||
counter += speed
|
||||
time.sleep(0.05)
|
||||
|
||||
def rotate_text_left_continuous(self, text, y, color=RAINBOW[0], speed=1.0, duration=10):
|
||||
"""
|
||||
Continuous left rotation - text wraps around seamlessly
|
||||
|
||||
Args:
|
||||
text: Text to display
|
||||
y: Y position (fixed)
|
||||
color: Text color
|
||||
speed: Movement speed
|
||||
duration: How long to run animation in seconds
|
||||
"""
|
||||
start_time = time.time()
|
||||
text_width = len(text) * (self.font_width + 1)
|
||||
position = 0
|
||||
|
||||
while time.time() - start_time < duration:
|
||||
self.clear()
|
||||
|
||||
# Draw text at current position
|
||||
for i, char in enumerate(text):
|
||||
char_x = int(position + (i * (self.font_width + 1)))
|
||||
# Handle wrapping
|
||||
if char_x < -self.font_width:
|
||||
char_x += self.MATRIX_WIDTH + text_width
|
||||
if 0 <= char_x < self.MATRIX_WIDTH:
|
||||
self.draw_letter(char, char_x, y, color)
|
||||
|
||||
self.write()
|
||||
|
||||
# Move left and wrap around
|
||||
position -= speed
|
||||
if position < -text_width:
|
||||
position = self.MATRIX_WIDTH
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
def draw_rectangle(self, x, y, width, height, color, fill=False):
|
||||
"""
|
||||
Draw a rectangle
|
||||
|
||||
Args:
|
||||
x: Top-left X position
|
||||
y: Top-left Y position
|
||||
width: Rectangle width
|
||||
height: Rectangle height
|
||||
color: RGB color tuple
|
||||
fill: Whether to fill the rectangle
|
||||
"""
|
||||
if fill:
|
||||
for i in range(height):
|
||||
for j in range(width):
|
||||
self.set_pixel(x + j, y + i, color)
|
||||
else:
|
||||
# Top and bottom edges
|
||||
for i in range(width):
|
||||
self.set_pixel(x + i, y, color)
|
||||
self.set_pixel(x + i, y + height - 1, color)
|
||||
# Left and right edges
|
||||
for i in range(height):
|
||||
self.set_pixel(x, y + i, color)
|
||||
self.set_pixel(x + width - 1, y + i, color)
|
||||
|
||||
def draw_line(self, x1, y1, x2, y2, color):
|
||||
"""
|
||||
Draw a line using Bresenham's algorithm
|
||||
|
||||
Args:
|
||||
x1, y1: Start coordinates
|
||||
x2, y2: End coordinates
|
||||
color: RGB color tuple
|
||||
"""
|
||||
dx = abs(x2 - x1)
|
||||
dy = abs(y2 - y1)
|
||||
sx = 1 if x1 < x2 else -1
|
||||
sy = 1 if y1 < y2 else -1
|
||||
err = dx - dy
|
||||
|
||||
while True:
|
||||
self.set_pixel(x1, y1, color)
|
||||
if x1 == x2 and y1 == y2:
|
||||
break
|
||||
e2 = 2 * err
|
||||
if e2 > -dy:
|
||||
err -= dy
|
||||
x1 += sx
|
||||
if e2 < dx:
|
||||
err += dx
|
||||
y1 += sy
|
||||
|
||||
|
||||
# Example usage
|
||||
if __name__ == '__main__':
|
||||
# Create display instance
|
||||
display = NeoPixel_64x64()
|
||||
|
||||
print('LED Matrix Display Initialized')
|
||||
print(get_datetime_string())
|
||||
print(f'German time: {get_german_time_ticks()}')
|
||||
print(f'German date: {get_german_date_ticks()}')
|
||||
|
||||
# Demo various functions
|
||||
display.show_hello()
|
||||
time.sleep(3)
|
||||
|
||||
display.vertical_floating_text('HELLO', 30, RAINBOW[0], 5, 0.15, 5)
|
||||
display.horizontal_floating_text('FLOAT', 28, RAINBOW[1], 10, 0.1, 5)
|
||||
display.rotate_text_left_continuous('ROTATE FLOAT', 28, speed=8.0, duration=5)
|
||||
|
||||
# Draw some shapes
|
||||
display.clear()
|
||||
display.draw_rectangle(5, 5, 10, 10, RAINBOW[0])
|
||||
display.draw_rectangle(20, 20, 15, 8, RAINBOW[2], fill=True)
|
||||
display.draw_line(0, 0, 63, 63, RAINBOW[4])
|
||||
display.write()
|
||||
0
app/utils/__init__.py
Normal file
0
app/utils/__init__.py
Normal file
98
app/utils/colors.py
Normal file
98
app/utils/colors.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# colors.py - Color library for LED matrix
|
||||
|
||||
# Basic Colors
|
||||
RED = (255, 0, 0)
|
||||
GREEN = (0, 255, 0)
|
||||
BLUE = (0, 0, 255)
|
||||
|
||||
# Primary Colors
|
||||
YELLOW = (255, 255, 0)
|
||||
MAGENTA = (255, 0, 255)
|
||||
CYAN = (0, 255, 255)
|
||||
|
||||
# White and Black
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
|
||||
# Grayscale
|
||||
GRAY = (128, 128, 128)
|
||||
LIGHT_GRAY = (192, 192, 192)
|
||||
DARK_GRAY = (64, 64, 64)
|
||||
|
||||
# Warm Colors
|
||||
ORANGE = (255, 165, 0)
|
||||
PINK = (255, 192, 203)
|
||||
HOT_PINK = (255, 105, 180)
|
||||
CORAL = (255, 127, 80)
|
||||
TOMATO = (255, 99, 71)
|
||||
|
||||
# Cool Colors
|
||||
PURPLE = (128, 0, 128)
|
||||
INDIGO = (75, 0, 130)
|
||||
VIOLET = (238, 130, 238)
|
||||
LAVENDER = (230, 230, 250)
|
||||
|
||||
# Earth Tones
|
||||
BROWN = (165, 42, 42)
|
||||
CHOCOLATE = (210, 105, 30)
|
||||
SANDY_BROWN = (244, 164, 96)
|
||||
GOLD = (255, 215, 0)
|
||||
|
||||
# Bright Colors
|
||||
LIME = (0, 255, 0)
|
||||
AQUA = (0, 255, 255)
|
||||
TURQUOISE = (64, 224, 208)
|
||||
SPRING_GREEN = (0, 255, 127)
|
||||
|
||||
# Pastel Colors
|
||||
PASTEL_RED = (255, 128, 128)
|
||||
PASTEL_GREEN = (128, 255, 128)
|
||||
PASTEL_BLUE = (128, 128, 255)
|
||||
PASTEL_YELLOW = (255, 255, 128)
|
||||
PASTEL_PURPLE = (255, 128, 255)
|
||||
PASTEL_CYAN = (128, 255, 255)
|
||||
|
||||
# Neon Colors
|
||||
NEON_RED = (255, 0, 0)
|
||||
NEON_GREEN = (57, 255, 20)
|
||||
NEON_BLUE = (0, 0, 255)
|
||||
NEON_YELLOW = (255, 255, 0)
|
||||
NEON_PINK = (255, 0, 128)
|
||||
NEON_ORANGE = (255, 128, 0)
|
||||
|
||||
# Rainbow Colors (for rainbow effects)
|
||||
RAINBOW = [
|
||||
(255, 0, 0), # Red
|
||||
(255, 127, 0), # Orange
|
||||
(255, 255, 0), # Yellow
|
||||
(0, 255, 0), # Green
|
||||
(0, 0, 255), # Blue
|
||||
(75, 0, 130), # Indigo
|
||||
(148, 0, 211), # Violet
|
||||
]
|
||||
|
||||
# Holiday Colors
|
||||
CHRISTMAS_RED = (255, 0, 0)
|
||||
CHRISTMAS_GREEN = (0, 255, 0)
|
||||
HALLOWEEN_ORANGE = (255, 140, 0)
|
||||
HALLOWEEN_PURPLE = (128, 0, 128)
|
||||
|
||||
|
||||
# Utility function to create custom colors
|
||||
def rgb(r, g, b):
|
||||
"""Create a color from RGB values (0-255)"""
|
||||
return (r, g, b)
|
||||
|
||||
|
||||
def hex_to_rgb(hex_color):
|
||||
"""Convert hex color (#RRGGBB) to RGB tuple"""
|
||||
hex_color = hex_color.lstrip('#')
|
||||
return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
|
||||
|
||||
|
||||
def fade_color(color1, color2, factor):
|
||||
"""Fade between two colors (factor 0.0 to 1.0)"""
|
||||
r = int(color1[0] + (color2[0] - color1[0]) * factor)
|
||||
g = int(color1[1] + (color2[1] - color1[1]) * factor)
|
||||
b = int(color1[2] + (color2[2] - color1[2]) * factor)
|
||||
return (r, g, b)
|
||||
37
app/utils/system_load.py
Normal file
37
app/utils/system_load.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import gc
|
||||
import time
|
||||
|
||||
|
||||
def show_system_load():
|
||||
"""Display basic system load information"""
|
||||
gc.collect() # Run garbage collection first
|
||||
|
||||
mem_free = gc.mem_free()
|
||||
mem_alloc = gc.mem_alloc()
|
||||
mem_total = mem_free + mem_alloc
|
||||
mem_usage = (mem_alloc / mem_total) * 100 if mem_total > 0 else 0
|
||||
|
||||
print('=== System Load ===')
|
||||
print(f'Memory: {mem_alloc}/{mem_total} bytes ({mem_usage:.1f}%)')
|
||||
print(f'Free: {mem_free} bytes')
|
||||
print(f'Garbage: {gc.mem_free() - mem_free} bytes')
|
||||
|
||||
try:
|
||||
# CPU load approximation (not available on all ports)
|
||||
start_time = time.ticks_ms()
|
||||
# Do some work to measure CPU
|
||||
for i in range(1000):
|
||||
_ = i * i
|
||||
end_time = time.ticks_ms()
|
||||
cpu_time = time.ticks_diff(end_time, start_time)
|
||||
print(f'CPU load: ~{cpu_time}ms for 1000 iterations')
|
||||
except (AttributeError, TypeError, ValueError) as e:
|
||||
print(f'CPU measurement not available: {e}')
|
||||
|
||||
print('==================')
|
||||
|
||||
|
||||
# Run periodically
|
||||
while True:
|
||||
show_system_load()
|
||||
time.sleep(5)
|
||||
84
app/utils/utils.py
Normal file
84
app/utils/utils.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import time
|
||||
|
||||
|
||||
def get_datetime_string(format='full'):
|
||||
"""
|
||||
Return date/time as string with different formats
|
||||
|
||||
Args:
|
||||
format: "full", "date", "time", "short", "ticks"
|
||||
"""
|
||||
try:
|
||||
year, month, day, hour, minute, second, weekday, yearday = time.localtime()
|
||||
|
||||
if format == 'full':
|
||||
return f'{year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}'
|
||||
elif format == 'date':
|
||||
return f'{year:04d}-{month:02d}-{day:02d}'
|
||||
elif format == 'time':
|
||||
return f'{hour:02d}:{minute:02d}:{second:02d}'
|
||||
elif format == 'short':
|
||||
return f'{month:02d}/{day:02d} {hour:02d}:{minute:02d}'
|
||||
else:
|
||||
return f'Ticks: {time.ticks_ms()} ms'
|
||||
|
||||
except:
|
||||
return f'Ticks: {time.ticks_ms()} ms'
|
||||
|
||||
|
||||
def get_german_datetime():
|
||||
"""Return German date and time"""
|
||||
try:
|
||||
year, month, day, hour, minute, second, weekday, yearday = time.localtime()
|
||||
|
||||
weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
|
||||
weekday_name = weekdays[weekday]
|
||||
|
||||
return f'{weekday_name}.{day:02d}.{month:02d}.{year} {hour:02d}:{minute:02d}'
|
||||
|
||||
except:
|
||||
ticks = time.ticks_ms() // 1000
|
||||
return f'Zeit: {ticks} sek'
|
||||
|
||||
|
||||
def get_german_timestamp_short():
|
||||
"""Get German timestamp with short months (for Wokwi)"""
|
||||
ticks = time.ticks_ms()
|
||||
day = (ticks // 86400000) % 31 + 1
|
||||
month = (ticks // 2592000000) % 12 + 1
|
||||
hour = (ticks // 3600000) % 24
|
||||
minute = (ticks // 60000) % 60
|
||||
|
||||
months = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
||||
month_name = months[month - 1]
|
||||
|
||||
return f'{day}.{month_name} {hour:02d}:{minute:02d}'
|
||||
|
||||
|
||||
def get_german_time_ticks():
|
||||
"""Get German time using ticks (works in Wokwi)"""
|
||||
ticks = time.ticks_ms()
|
||||
|
||||
# Simulate time progression
|
||||
total_seconds = ticks // 1000
|
||||
hours = (total_seconds // 3600) % 24
|
||||
minutes = (total_seconds // 60) % 60
|
||||
seconds = total_seconds % 60
|
||||
|
||||
return f'{hours:02d}:{minutes:02d}:{seconds:02d}'
|
||||
|
||||
|
||||
def get_german_date_ticks():
|
||||
"""Get German date using ticks"""
|
||||
ticks = time.ticks_ms()
|
||||
|
||||
# Simulate date progression (starting from Jan 15, 2024)
|
||||
days_passed = ticks // (24 * 3600 * 1000)
|
||||
day = 15 + (days_passed % 28) # Simple month simulation
|
||||
month = 1 + (days_passed // 28) % 12
|
||||
year = 2024 + (days_passed // (28 * 12))
|
||||
|
||||
months = ['JAN', 'FEB', 'MAR', 'APR', 'MAI', 'JUN', 'JUL', 'AUG', 'SEP', 'OKT', 'NOV', 'DEZ']
|
||||
month_name = months[month - 1]
|
||||
|
||||
return f'{day:02d}.{month_name}.{str(year)[-2:]}'
|
||||
108
app/web/wlan.py
Normal file
108
app/web/wlan.py
Normal file
@@ -0,0 +1,108 @@
|
||||
import time
|
||||
import network
|
||||
import urequests
|
||||
from ..classes.location import Location
|
||||
from ..classes.weather import CurrentCondition, Weather
|
||||
|
||||
API_KEY = '3545ce42d0ba436e8dc164532250410'
|
||||
ACTUAL_WEATHER = 'https://api.weatherapi.com/v1/current.json?key={{key}}&q={{city}}&aqi=yes'
|
||||
|
||||
WEATHER_QUERY_MOCK = {
|
||||
'location': {
|
||||
'name': 'Grosshansdorf',
|
||||
'region': 'Schleswig-Holstein',
|
||||
'country': 'Germany',
|
||||
'lat': 53.6667,
|
||||
'lon': 10.2833,
|
||||
'tz_id': 'Europe/Berlin',
|
||||
'localtime_epoch': 1760779328,
|
||||
'localtime': '2025-10-18 11:22',
|
||||
},
|
||||
'current': {
|
||||
'last_updated_epoch': 1760778900,
|
||||
'last_updated': '2025-10-18 11:15',
|
||||
'temp_c': 8.3,
|
||||
'temp_f': 46.9,
|
||||
'is_day': 1,
|
||||
'condition': {
|
||||
'text': 'Sonnig',
|
||||
'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png',
|
||||
'code': 1000,
|
||||
},
|
||||
'wind_mph': 2.5,
|
||||
'wind_kph': 4.0,
|
||||
'wind_degree': 31,
|
||||
'wind_dir': 'NNE',
|
||||
'pressure_mb': 1029.0,
|
||||
'pressure_in': 30.39,
|
||||
'precip_mm': 0.0,
|
||||
'precip_in': 0.0,
|
||||
'humidity': 76,
|
||||
'cloud': 0,
|
||||
'feelslike_c': 8.2,
|
||||
'feelslike_f': 46.8,
|
||||
'windchill_c': 10.0,
|
||||
'windchill_f': 50.0,
|
||||
'heatindex_c': 9.9,
|
||||
'heatindex_f': 49.8,
|
||||
'dewpoint_c': 2.2,
|
||||
'dewpoint_f': 35.9,
|
||||
'vis_km': 10.0,
|
||||
'vis_miles': 6.0,
|
||||
'uv': 0.9,
|
||||
'gust_mph': 2.8,
|
||||
'gust_kph': 4.6,
|
||||
'air_quality': {
|
||||
'co': 163.678,
|
||||
'no2': 7.278,
|
||||
'o3': 47.0,
|
||||
'so2': 1.178,
|
||||
'pm2_5': 5.778,
|
||||
'pm10': 7.178,
|
||||
'us-epa-index': 1,
|
||||
'gb-defra-index': 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class Wlan:
|
||||
def __init__(self, ssid, password):
|
||||
self.ssid = ssid
|
||||
self.password = password
|
||||
|
||||
def connect(self):
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
wlan.connect(self.ssid, self.password)
|
||||
|
||||
while not wlan.isconnected:
|
||||
print('connecting, please wait ...')
|
||||
time.sleep(1)
|
||||
|
||||
print('connected! IP=', wlan.ifconfig()[0])
|
||||
|
||||
def actual_weather(self, city='grosshansdorf', lang='de', test_mode=False) -> Weather:
|
||||
weather_url = (
|
||||
f'https://api.weatherapi.com/v1/current.json?key={API_KEY}&q={city}&aqi=yes&lang={lang}'
|
||||
)
|
||||
print(f'query: {weather_url}')
|
||||
|
||||
if not test_mode:
|
||||
r = urequests.get(weather_url)
|
||||
|
||||
print('Status-Code:', r.status_code)
|
||||
json_resp = r.json()
|
||||
print(json_resp.keys())
|
||||
|
||||
r.close()
|
||||
else:
|
||||
print('Status-Code: test_mode')
|
||||
json_resp = WEATHER_QUERY_MOCK
|
||||
|
||||
loc = Location(**json_resp['location'])
|
||||
cc = CurrentCondition(**json_resp['current'])
|
||||
|
||||
weather = Weather(location=loc, current=cc)
|
||||
|
||||
return weather
|
||||
Reference in New Issue
Block a user