Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Add] Ping and Weather custom sensor + ColoredFlat Theme #510

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
24 changes: 18 additions & 6 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
---
config:
# Configuration values to set up basic communication
# Set your COM port e.g. COM3 for Windows, /dev/ttyACM0 for Linux...
# Use AUTO for COM port auto-discovery (may not work on every setup)
# COM_PORT: "/dev/ttyACM0"
# COM_PORT: "COM3"
COM_PORT: "AUTO"
COM_PORT: AUTO

# Theme to use (located in res/themes)
# Use the name of the folder as value
THEME: 3.5inchTheme2
THEME: ColoredFlat

# Hardware sensors reading
# Choose the appropriate method for reading your hardware sensors:
Expand All @@ -23,8 +22,21 @@ config:
# Linux/MacOS interfaces are named "eth0", "wlan0", "wlp1s0", "enp2s0"...
# For Windows use the interfaces pretty name: "Ethernet 2", "Wi-Fi", ...
# Leave the fields empty if the card does not exist on your setup
ETH: "" # Ethernet Card
WLO: "" # Wi-Fi Card
ETH: Ethernet # Ethernet Card
WLO: Wi-Fi # Wi-Fi Card

# Used to calculate your ping.
PING: 8.8.8.8

# For weather, you can use for example https://www.latlong.net/
LATITUDE: 45.75
LONGITUDE: 4.85
# OpenWeatherMap API KEY. Can be obtained by creating a free account on https://home.openweathermap.org/users/sign_up. You need to subscreibe to the 3.0 OneCallAPI that has 1000 free daily calls
API_KEY: abcdef
# Units used to display temperatures (metric - °C, imperial - °F, standard - °K)
WEATHER_UNITS: metric
# Language is used by the API. Find more here https://openweathermap.org/api/one-call-3#multi
LANGUAGE: fr

display:
# Display revision:
Expand All @@ -35,7 +47,7 @@ display:
# - SIMU for 3.5" simulated LCD (image written in screencap.png)
# - SIMU5 for 5" simulated LCD
# To identify your smart screen: https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions
REVISION: A
REVISION: C

# Display Brightness
# Set this as the desired %, 0 being completely dark and 100 being max brightness
Expand Down
6 changes: 6 additions & 0 deletions library/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ def CustomStats():
stats.Custom.stats()


@async_job("Weather_Stats")
@schedule(timedelta(seconds=config.THEME_DATA['STATS'].get('WEATHER', {}).get("INTERVAL", 0)).total_seconds())
def WeatherStats():
# logger.debug("Refresh Weather data")
stats.Weather.stats()

@async_job("Queue_Handler")
@schedule(timedelta(milliseconds=1).total_seconds())
def QueueHandler():
Expand Down
37 changes: 36 additions & 1 deletion library/sensors/sensors_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@

import math
import platform
import requests
from abc import ABC, abstractmethod
from typing import List
from ping3 import ping, verbose_ping
from datetime import datetime
import library.config as config


# Custom data classes must be implemented in this file, inherit the CustomDataSource and implement its 2 methods
Expand All @@ -47,6 +51,37 @@ def last_values(self) -> List[float]:
# If you do not want to draw a line graph or if your custom data has no numeric values, keep this function empty
pass

# Custom data class to measure ping to google.fr
class Ping(CustomDataSource):
# This list is used to store the last 500 values to display a line graph
last_val = [math.nan] * 500 # By default, it is filed with math.nan values to indicate there is no data stored

def as_numeric(self) -> float:
# Measure the ping
try:
result = ping(config.CONFIG_DATA['config'].get('PING', "8.8.8.8"))*1000
if result is not None:
# Store the value to the history list that will be used for line graph
self.last_val.append(result)
# Also remove the oldest value from history list
self.last_val.pop(0)
return result
else:
self.last_val.append(9999)
self.last_val.pop(0)
return 9999 # Return 0 if ping fails
except Exception as e:
self.last_val.append(9999)
self.last_val.pop(0)
return 9999

def as_string(self) -> str:
# Format the ping result as a string
return f'{self.as_numeric():4.0f} ms'

def last_values(self) -> List[float]:
# Since there is no historical data for ping, return an empty list
return self.last_val

# Example for a custom data class that has numeric and text values
class ExampleCustomNumericData(CustomDataSource):
Expand Down Expand Up @@ -95,4 +130,4 @@ def as_string(self) -> str:

def last_values(self) -> List[float]:
# If a custom data class only has text values, it won't be possible to display line graph
pass
pass
75 changes: 75 additions & 0 deletions library/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import babel.dates
from psutil._common import bytes2human
import requests

import library.config as config
from library.display import display
Expand Down Expand Up @@ -767,3 +768,77 @@ def stats():
theme_data = config.THEME_DATA['STATS']['CUSTOM'][custom_stat].get("LINE_GRAPH", None)
if theme_data is not None and last_values is not None:
display_themed_line_graph(theme_data=theme_data, values=last_values)

class Weather:
@staticmethod
def stats():
WEATHER_UNITS = {'metric': '°C', 'imperial': '°F', 'standard': '°K'}

weather_theme_data = config.THEME_DATA['STATS'].get('WEATHER', {})
wtemperature_theme_data = weather_theme_data.get('TEMPERATURE', {}).get('TEXT', {})
wfelt_theme_data = weather_theme_data.get('TEMPERATURE_FELT', {}).get('TEXT', {})
wupdatetime_theme_data = weather_theme_data.get('UPDATE_TIME', {}).get('TEXT', {})
wdescription_theme_data = weather_theme_data.get('WEATHER_DESCRIPTION', {}).get('TEXT', {})
whumidity_theme_data = weather_theme_data.get('HUMIDITY', {}).get('TEXT', {})

# Retrieve information used to center description, if needed
center_description_length = 40
if 'CENTER_LENGTH' in wdescription_theme_data:
center_description_length = wdescription_theme_data['CENTER_LENGTH']

activate = True if wtemperature_theme_data.get("SHOW") or wfelt_theme_data.get("SHOW") or wupdatetime_theme_data.get("SHOW") or wdescription_theme_data.get("SHOW") or whumidity_theme_data.get("SHOW") else False

if activate:
if HW_SENSORS in ["STATIC", "STUB"]:
temp = "17.5°C"
feel = "(17.2°C)"
desc = "Cloudy"
time = "@15:33"
humidity = "45%"
if wdescription_theme_data['CENTER_LENGTH']:
desc = "x"*center_description_length
else:
# API Parameters
lat = config.CONFIG_DATA['config'].get('LATITUDE', "")
lon = config.CONFIG_DATA['config'].get('LONGITUDE', "")
api_key = config.CONFIG_DATA['config'].get('API_KEY', "")
units = config.CONFIG_DATA['config'].get('WEATHER_UNITS', "metric")
lang = config.CONFIG_DATA['config'].get('LANGUAGE', "en")
deg = WEATHER_UNITS.get(units, '°?')
if api_key:
url = f'https://api.openweathermap.org/data/3.0/onecall?lat={lat}&lon={lon}&exclude=minutely,hourly,daily,alerts&appid={api_key}&units={units}&lang={lang}'
try:
response = requests.get(url)
if response.status_code == 200:
try:
data = response.json()
temp = f"{data['current']['temp']:.1f}{deg}"
feel = f"({data['current']['feels_like']:.1f}{deg})"
desc = data['current']['weather'][0]['description'].capitalize()
if wdescription_theme_data['CENTER_LENGTH']:
desc = desc.center(center_description_length)
humidity = f"{data['current']['humidity']:.0f}%"
now = datetime.datetime.now()
time = f"@{now.hour:02d}:{now.minute:02d}"
except Exception as e:
logger.error(str(e))
desc = "Error fetching weather"
else:
print(f"Failed to fetch weather data. Status code: {response.status_code}")
print(f"Response content: {response.content}")
logger.error(response.text)
desc = response.json().get('message')
except:
desc = "Connection error"

if activate:
# Display Temperature
display_themed_value(theme_data=wtemperature_theme_data, value=temp)
# Display Temperature Felt
display_themed_value(theme_data=wfelt_theme_data, value=feel)
# Display Update Time
display_themed_value(theme_data=wupdatetime_theme_data, value=time)
# Display Humidity
display_themed_value(theme_data=whumidity_theme_data, value=humidity)
# Display Weather Description
display_themed_value(theme_data=wdescription_theme_data, value=desc)
1 change: 1 addition & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ def on_win32_wm_event(hWnd, msg, wParam, lParam):
scheduler.NetStats()
scheduler.DateStats()
scheduler.CustomStats()
scheduler.WeatherStats()
scheduler.QueueHandler()

if tray_icon and platform.system() == "Darwin": # macOS-specific
Expand Down
11 changes: 9 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Python packages requirements
Pillow~=10.3.0 # Image generation
Pillow~=10.2.0 # Image generation
pyserial~=3.5 # Serial link to communicate with the display
PyYAML~=6.0.1 # For themes files
psutil~=5.9.8 # CPU / disk / network metrics
Expand All @@ -8,9 +8,10 @@ babel~=2.14.0 # Date/time formatting
ruamel.yaml~=0.18.6 # For configuration editor
sv-ttk~=2.6.0 # Tk Sun Valley theme for configuration editor


# Efficient image serialization
numpy~=1.24.4; python_version < "3.9" # For Python 3.8 max.
numpy~=1.26.4; python_version >= "3.9" # For Python 3.9+
numpy~=1.26.0; python_version >= "3.9" # For Python 3.9+

# For Nvidia GPU on all platforms
GPUtil~=1.4.0; python_version < "3.12"
Expand All @@ -27,3 +28,9 @@ pyadl~=0.1; sys_platform=="win32"
# Following packages are for LibreHardwareMonitor integration on Windows
pythonnet~=3.0.3; sys_platform=="win32"
pywin32>=306; sys_platform=="win32"

# for weather
requests

# for ping
ping3~=4.0.4
Binary file added res/themes/ColoredFlat/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/themes/ColoredFlat/background.xcf
Binary file not shown.
Binary file added res/themes/ColoredFlat/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/themes/ColoredFlat/telecharger-arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading