diff --git a/app/display/emoji/emoji_16x16.py b/app/display/emoji/emoji_16x16.py index 44e5bb1..8eb3482 100644 --- a/app/display/emoji/emoji_16x16.py +++ b/app/display/emoji/emoji_16x16.py @@ -1,7 +1,7 @@ # Emoji symbols for LED matrix (16x16) emoji_16x16 = { - # Basic Smileys - 'πŸ˜€': [ + # === SMILEYS & EMOTIONS === + 'πŸ˜€': [ # Grinning Face 0x07E0, 0x1FF8, 0x3FFC, @@ -18,8 +18,8 @@ emoji_16x16 = { 0x1FF8, 0x07E0, 0x0000, - ], # Grinning face (circle outline) - '😊': [ + ], + '😊': [ # Smiling Face with Smiling Eyes 0x07E0, 0x1FF8, 0x3FFC, @@ -36,8 +36,8 @@ emoji_16x16 = { 0x3FFC, 0x1FF8, 0x07E0, - ], # Smiling face - 'πŸ˜‚': [ + ], + 'πŸ˜‚': [ # Face with Tears of Joy 0x07E0, 0x1FF8, 0x3FFC, @@ -54,8 +54,8 @@ emoji_16x16 = { 0x3FFC, 0x1FF8, 0x07E0, - ], # Laughing with tears - '😍': [ + ], + '😍': [ # Smiling Face with Heart-Eyes 0x07E0, 0x1FF8, 0x3FFC, @@ -72,8 +72,8 @@ emoji_16x16 = { 0x3FFC, 0x1FF8, 0x07E0, - ], # Heart eyes - '😎': [ + ], + '😎': [ # Smiling Face with Sunglasses 0x07E0, 0x1FF8, 0x3FFC, @@ -90,9 +90,45 @@ emoji_16x16 = { 0x3FFC, 0x1FF8, 0x07E0, - ], # Cool sunglasses - # Hearts - '❀️': [ + ], + '😒': [ # Crying Face + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7C3E, + 0xF81F, + 0xF00F, + 0xF3CF, + 0xF3CF, + 0xF00F, + 0xF99F, + 0x7C3E, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + ], + '😠': [ # Angry Face + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7C3E, + 0xF81F, + 0xF3CF, + 0xE667, + 0xE667, + 0xF3CF, + 0xF81F, + 0x7C3E, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + ], + # === HEARTS === + '❀️': [ # Red Heart 0x0000, 0x0000, 0x0C30, @@ -109,9 +145,27 @@ emoji_16x16 = { 0x0F80, 0x0700, 0x0000, - ], # Red heart - # Weather & Nature - 'β˜€οΈ': [ + ], + 'πŸ’™': [ # Blue Heart + 0x0000, + 0x0000, + 0x0C30, + 0x1E78, + 0x3FFC, + 0x7FFE, + 0x7FFE, + 0xFFFE, + 0xFFFC, + 0x7FF8, + 0x7FF0, + 0x3FE0, + 0x1FC0, + 0x0F80, + 0x0700, + 0x0000, + ], + # === WEATHER & NATURE === + 'β˜€οΈ': [ # Sun 0x8001, 0x4002, 0x2004, @@ -128,8 +182,8 @@ emoji_16x16 = { 0x2004, 0x4002, 0x8001, - ], # Sun with detailed rays - 'πŸŒ™': [ + ], + 'πŸŒ™': [ # Crescent Moon 0x0000, 0x1F80, 0x3FC0, @@ -146,8 +200,8 @@ emoji_16x16 = { 0xFC00, 0xF800, 0x0000, - ], # Crescent moon - '⭐': [ + ], + '⭐': [ # Star 0x0180, 0x0180, 0x03C0, @@ -164,9 +218,27 @@ emoji_16x16 = { 0x03C0, 0x0180, 0x0180, - ], # Star - # Objects - 'πŸ“±': [ + ], + '☁️': [ # Cloud + 0x0000, + 0x0000, + 0x0F00, + 0x1F80, + 0x3FC0, + 0x7FE0, + 0x7FE0, + 0xFFF0, + 0xFFF0, + 0xFFF0, + 0x7FE0, + 0x7FE0, + 0x3FC0, + 0x1F80, + 0x0F00, + 0x0000, + ], + # === TECHNOLOGY === + 'πŸ“±': [ # Mobile Phone 0xFFFF, 0x8001, 0x8001, @@ -183,8 +255,8 @@ emoji_16x16 = { 0x8001, 0x8001, 0xFFFF, - ], # Smartphone - 'πŸ’»': [ + ], + 'πŸ’»': [ # Laptop 0x0000, 0x7FFE, 0x4002, @@ -201,65 +273,8 @@ emoji_16x16 = { 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 - 'πŸ”’': [ + ], + 'πŸ”’': [ # Lock 0x0FC0, 0x1FE0, 0x3FF0, @@ -276,28 +291,82 @@ emoji_16x16 = { 0x3FF0, 0x3FF0, 0x3FF0, - ], # Lock - # Vehicles - 'πŸš—': [ + ], + 'πŸ”‘': [ # Key 0x0000, 0x0000, - 0x0FC0, - 0x1FE0, - 0x3FF0, - 0x3FF0, - 0x3FF0, - 0x3FF0, - 0x3FF0, - 0x3FF0, - 0x3FF0, - 0x3FF0, - 0x1FE0, - 0x0FC0, + 0x0F00, + 0x1F80, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + 0x3FC0, + ], + # === ANIMALS === + '🐱': [ # Cat Face + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7FFE, + 0x6FF6, + 0x6FF6, + 0x6FF6, + 0x6FF6, + 0x6FF6, + 0x7FFE, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + 0x0000, + ], + '🐢': [ # Dog Face + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7FFE, + 0x6FF6, + 0x6FF6, + 0x6FF6, + 0x6FF6, + 0x6FF6, + 0x7FFE, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + 0x0000, + ], + '🐦': [ # Bird 0x0000, 0x0000, - ], # Car - # Sports - '⚽': [ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + ], + # === FOOD === + 'πŸ•': [ # Pizza 0x07E0, 0x1FF8, 0x3FFC, @@ -314,9 +383,101 @@ emoji_16x16 = { 0x1FF8, 0x07E0, 0x0000, - ], # Soccer ball - # Holidays - 'πŸŽ„': [ + ], + '🍎': [ # Red Apple + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + ], + # === VEHICLES === + 'πŸš—': [ # Car + 0x0000, + 0x0000, + 0x0FC0, + 0x1FE0, + 0x3FF0, + 0x3FF0, + 0x3FF0, + 0x3FF0, + 0x3FF0, + 0x3FF0, + 0x3FF0, + 0x3FF0, + 0x1FE0, + 0x0FC0, + 0x0000, + 0x0000, + ], + '✈️': [ # Airplane + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + ], + # === SPORTS === + '⚽': [ # Soccer Ball + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + 0x0000, + ], + 'πŸ€': [ # Basketball + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + 0x0000, + ], + # === HOLIDAYS === + 'πŸŽ„': [ # Christmas Tree 0x0180, 0x03C0, 0x03C0, @@ -333,5 +494,23 @@ emoji_16x16 = { 0x03C0, 0x03C0, 0x03C0, - ], # Christmas tree + ], + 'πŸŽƒ': [ # Jack-O-Lantern + 0x07E0, + 0x1FF8, + 0x3FFC, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x7FFE, + 0x3FFC, + 0x1FF8, + 0x07E0, + 0x0000, + ], } diff --git a/app/display/fonts/font_5x7_opt.py b/app/display/fonts/font_5x7_opt.py index 4288f5c..268abaa 100644 --- a/app/display/fonts/font_5x7_opt.py +++ b/app/display/fonts/font_5x7_opt.py @@ -221,9 +221,9 @@ char_width = { } -def get_char_width(char): +def get_char_width(char, default_witdth=5): """Get the display width of a character for proper spacing""" - return char_width.get(char, 5) # Default to 5 if character not found + return char_width.get(char, default_witdth) # Default to 5 if character not found def get_text_width(text): diff --git a/app/display/fonts/fonts_utils.py b/app/display/fonts/fonts_utils.py index 297e891..338f342 100644 --- a/app/display/fonts/fonts_utils.py +++ b/app/display/fonts/fonts_utils.py @@ -6,6 +6,7 @@ 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 +from ...utils.utils import number_to_bitarray_msb fonts_meta_ = { 3: {'w': 3, 'h': 5}, @@ -34,3 +35,24 @@ def fonts_meta(font): return fonts_meta_[16] else: return None + + +def char_width(char_matrix) -> int: + """Berechnung der Bits fΓΌr die Zeichenbreite + + Args: + char_matrix (int): Zeichen als Array[int] + + Returns: + int: Anzahl Bits fΓΌr die Zeichenbreite + """ + max_val = max(char_matrix) + + val = max_val + cw = 0 + while 0xFFFFFFFF & val: + """rechts shiften, bis alles Nullen da sind""" + val >>= 1 + cw += 1 + + return cw diff --git a/app/display/neopixel_64x64.py b/app/display/neopixel_64x64.py index 0d2943d..0742201 100644 --- a/app/display/neopixel_64x64.py +++ b/app/display/neopixel_64x64.py @@ -1,6 +1,6 @@ from machine import Pin, RTC from neopixel import NeoPixel -from .fonts.fonts_utils import fonts_meta +from .fonts.fonts_utils import fonts_meta, char_width as charwidth from .fonts.font_5x7 import font_5x7 from .fonts.font_5x7_opt import font_5x7 as font_5x7_opt, get_char_width @@ -124,17 +124,20 @@ class NeoPixel_64x64(NeoPixel): color: RGB color tuple """ - # background for the letter (full font size) - [ - # print(xpos, ypos) - self.set_pixel(xpos, ypos, GRAY) - for xpos in range(x, x + 8) # 8 because full with of character representation - for ypos in range(y, y + self.font_height) - ] - if letter in self.selected_font: char_data = self.selected_font[letter] - char_width = get_char_width(letter) + # char_width = get_char_width(letter, default_witdth=16) + char_width = charwidth(char_data) + + # background for the letter (full font size) + [ + # print(xpos, ypos) + self.set_pixel(xpos, ypos, GRAY) + for xpos in range( + x, x + char_width + ) # 8 because full with of character representation + for ypos in range(y, y + self.font_height) + ] for row in range(self.font_height): row_data = char_data[row] diff --git a/app/utils/utils.py b/app/utils/utils.py index a90502a..24738b9 100644 --- a/app/utils/utils.py +++ b/app/utils/utils.py @@ -7,9 +7,9 @@ def show_byte_matrix(char, matrix): [print(f'{matrix_str[idx]} {number_to_bitarray_msb(byte)}') for idx, byte in enumerate(matrix)] -def number_to_bitarray_msb(number): - """Convert 8-bit number to bit array (MSB first)""" - return [(number >> i) & 1 for i in range(7, -1, -1)] +def number_to_bitarray_msb(number, bits=8): + """Convert 8/16-bit number to bit array (MSB first)""" + return [(number >> i) & 1 for i in range(bits - 1, -1, -1)] def is_letter_assigned_right(char, letter) -> bool: diff --git a/main.py b/main.py index f00dddd..56f8068 100644 --- a/main.py +++ b/main.py @@ -17,28 +17,23 @@ display = NeoPixel_64x64() def emoji_test(): display.clear() - # display.set_font(font_8x8) - # display.show_hello() - # display.rotate_text_left_continuous('FLOATING TEXT', 0, speed=8.0, duration=30) - - display.set_font(font_16x16) - display.draw_text('ABCD', 1, 1, color=GOLD) # try emoji display.set_font(emoji_8x8) - display.draw_text('πŸ˜€', 1, 20, color=GREEN) - display.draw_text('⭐', 1, 29) - display.draw_text('βœ…', 1, 38) - display.draw_text('😎', 1, 47, color=RED) - display.draw_text('πŸ’™', 10, 47) - display.draw_text('πŸ’š', 19, 47) - display.draw_text('πŸ’›', 28, 47) + display.write_text('πŸ˜€', 0, 0, color=GREEN) + display.write_text('πŸ˜‚', 0, 29) + # display.write_text('βœ…', 0, 38) + # display.write_text('😎', 0, 47, color=RED) + # display.write_text('πŸ’™', 10, 47) + # display.write_text('πŸ’š', 19, 47) + # display.write_text('πŸ’›', 28, 47) + + char_row = 'πŸ˜€' + utils.is_letter_assigned_right(char_row, emoji_8x8[char_row]) # try emoji - # display.set_font(emoji_16x16) - # display.draw_text('πŸ˜€', 10, 20, color=ORANGE) - - display.write() + display.set_font(emoji_16x16) + display.write_text('πŸŒ™', 0, 10, color=ORANGE) def weather_check(test_mode: bool = False): @@ -58,7 +53,7 @@ def weather_check(test_mode: bool = False): display.draw_text('weather data', 0, 16, color=RAINBOW[1]) display.write() - w_resp = wlan.actual_weather(test_mode=test_mode) + w_resp = wlan.actual_weather(lang='en', test_mode=test_mode) display.clear() @@ -77,10 +72,10 @@ def weather_check(test_mode: bool = False): display.write_text(f'{str(w_resp.current.condition.text)}Β°C', 0, ypos, color=RAINBOW[1]) ypos += delta display.write_text( - f'upd: {str(w_resp.current.last_updated)[-5:]}', 0, ypos, color=RAINBOW[2] + f'upd:{str(w_resp.current.last_updated)[-5:]}', 0, ypos, color=RAINBOW[2] ) ypos += delta - display.write_text(f'cur: {str(w_resp.location.localtime)[-5:]}', 0, ypos, color=RAINBOW[3]) + display.write_text(f'cur:{str(w_resp.location.localtime)[-5:]}', 0, ypos, color=RAINBOW[3]) ypos += 3 * delta display.write_text('ready.', 30, ypos, color=WHITE) @@ -106,10 +101,6 @@ def font_5x7_test() -> None: def bit_arrays(): - # def number_to_bitarray_msb(number): - # """Convert 8-bit number to bit array (MSB first)""" - # return [(number >> i) & 1 for i in range(7, -1, -1)] - # c = 'A' # print(c) # [print(utils.number_to_bitarray_msb(num)) for num in font_5x7[c]] diff --git a/restapi/mock-weather.json b/restapi/mock-weather.json index 6eeb63b..1263191 100644 --- a/restapi/mock-weather.json +++ b/restapi/mock-weather.json @@ -6,50 +6,50 @@ "lat": 53.6667, "lon": 10.2833, "tz_id": "Europe/Berlin", - "localtime_epoch": 1760977041, - "localtime": "2025-10-20 18:17" + "localtime_epoch": 1761209139, + "localtime": "2025-10-23 10:45" }, "current": { - "last_updated_epoch": 1760976900, - "last_updated": "2025-10-20 18:15", - "temp_c": 12.3, - "temp_f": 54.1, - "is_day": 0, + "last_updated_epoch": 1761209100, + "last_updated": "2025-10-23 10:45", + "temp_c": 12.4, + "temp_f": 54.3, + "is_day": 1, "condition": { - "text": "leichter Regenfall", - "icon": "//cdn.weatherapi.com/weather/64x64/night/296.png", - "code": 1183 + "text": "Light rain shower", + "icon": "//cdn.weatherapi.com/weather/64x64/day/353.png", + "code": 1240 }, - "wind_mph": 12.1, - "wind_kph": 19.4, - "wind_degree": 151, + "wind_mph": 13.6, + "wind_kph": 22.0, + "wind_degree": 147, "wind_dir": "SSE", - "pressure_mb": 999.0, - "pressure_in": 29.5, - "precip_mm": 0.0, - "precip_in": 0.0, - "humidity": 77, - "cloud": 100, + "pressure_mb": 983.0, + "pressure_in": 29.03, + "precip_mm": 2.34, + "precip_in": 0.09, + "humidity": 100, + "cloud": 75, "feelslike_c": 10.3, - "feelslike_f": 50.6, - "windchill_c": 10.1, - "windchill_f": 50.1, - "heatindex_c": 12.1, - "heatindex_f": 53.8, - "dewpoint_c": 7.7, - "dewpoint_f": 45.8, - "vis_km": 10.0, - "vis_miles": 6.0, + "feelslike_f": 50.5, + "windchill_c": 10.5, + "windchill_f": 50.9, + "heatindex_c": 12.6, + "heatindex_f": 54.6, + "dewpoint_c": 12.0, + "dewpoint_f": 53.6, + "vis_km": 8.0, + "vis_miles": 4.0, "uv": 0.0, - "gust_mph": 19.8, - "gust_kph": 31.9, + "gust_mph": 21.1, + "gust_kph": 33.9, "air_quality": { - "co": 171.678, - "no2": 9.778, - "o3": 54.0, - "so2": 1.678, - "pm2_5": 10.078, - "pm10": 12.578, + "co": 152.678, + "no2": 8.378, + "o3": 35.0, + "so2": 0.878, + "pm2_5": 7.878, + "pm10": 8.978, "us-epa-index": 1, "gb-defra-index": 1 } diff --git a/restapi/weather.http b/restapi/weather.http index cb074bb..33a6cec 100644 --- a/restapi/weather.http +++ b/restapi/weather.http @@ -1,5 +1,5 @@ @city = "grosshansdorf" -@lang = de +@lang = en @forecast_days = 3 # could be 60(mins) or 24(day) @time_period_forecast = 60