mqtt and other stuff to make it similar to departures generator

This commit is contained in:
Wiktor Przybylski 2024-12-01 22:35:40 +01:00
parent 38b6726e39
commit 950c678492
5 changed files with 96 additions and 23 deletions

View File

@ -2,4 +2,14 @@ OPENWEATHER_API_KEY=CHANGEME
LOCATION_ID=CHANGEME LOCATION_ID=CHANGEME
FLIPDOT_API=http://127.0.0.1/ FLIPDOT_API=http://127.0.0.1/
FLIPDOT_SLOTS=15 FLIPDOT_SLOTS=15
LUFTDATEN_CLOSEST_SENSOR=CHANGEME LUFTDATEN_CLOSEST_SENSOR=CHANGEME
MQTT_BROKER=127.0.0.1
MQTT_PASSWORD=CHANGEME
MQTT_PORT=1883
MQTT_TOPIC_BASE=flipdot/app/weather
MQTT_USERNAME=changeme
FLIPDOT_MQTT=True
FLIPDOT_POST=False
EVEN_DISTRIBUTION=False
TEXT_FONT=twin6
TEXT_ALIGN=right

View File

@ -1,19 +1,18 @@
FROM python:3.9-slim FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt /app
RUN pip install --no-cache-dir -r requirements.txt
RUN apt-get update && apt-get install --assume-yes \ RUN apt-get update && apt-get install --assume-yes \
cron \ cron \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
COPY . /app WORKDIR /app
COPY requirements.txt /app
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
RUN (echo "SHELL=/bin/bash" > /etc/cron.d/fetch_crl_cron) RUN (echo "SHELL=/bin/bash" > /etc/cron.d/fetch_crl_cron)
RUN (echo "BASH_ENV=/app/.env" >> /etc/cron.d/fetch_crl_cron) RUN (echo "BASH_ENV=/app/.env" >> /etc/cron.d/fetch_crl_cron)
RUN (echo "* * * * * root /usr/local/bin/python3 /app/app.py >> /var/log/cron.log 2>&1" >> /etc/cron.d/fetch_crl_cron) RUN (echo "*/30 * * * * root /usr/local/bin/python3 /app/app.py >> /var/log/cron.log 2>&1" >> /etc/cron.d/fetch_crl_cron)
RUN touch /var/log/cron.log RUN touch /var/log/cron.log

72
app.py
View File

@ -2,8 +2,10 @@ import requests
from datetime import datetime from datetime import datetime
import os import os
import logging import logging
import paho.mqtt.client as mqtt
import json
logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.DEBUG) logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s',level=logging.INFO)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# OpenWeather API settings # OpenWeather API settings
@ -14,6 +16,32 @@ FLIPDOT_API = os.getenv('FLIPDOT_API', 'http://127.0.0.1/')
FLIPDOT_SLOTS = int(os.getenv('FLIPDOT_SLOTS', 15)) FLIPDOT_SLOTS = int(os.getenv('FLIPDOT_SLOTS', 15))
LUFTDATEN_CLOSEST_SENSOR = os.getenv('LUFTDATEN_CLOSEST_SENSOR', '84121') LUFTDATEN_CLOSEST_SENSOR = os.getenv('LUFTDATEN_CLOSEST_SENSOR', '84121')
DAYS = os.getenv('DAYS', 3) DAYS = os.getenv('DAYS', 3)
is_mqtt = os.getenv('FLIPDOT_MQTT', 'False').lower() in ('true', '1', 't')
is_post = os.getenv('FLIPDOT_POST', 'False').lower() in ('true', '1', 't')
mqtt_broker = os.getenv('MQTT_BROKER', 'localhost')
mqtt_port = int(os.getenv('MQTT_PORT', 1883))
mqtt_topic_base = os.getenv('MQTT_TOPIC_BASE', 'flipdot/trash/changeme')
mqtt_username = os.getenv('MQTT_USERNAME', None)
mqtt_password = os.getenv('MQTT_PASSWORD', None)
even_distribution = os.getenv('EVEN_DISTRIBUTION', 'False').lower() in ('true', '1', 't')
text_font = os.getenv('TEXT_FONT', 'twin6')
text_align = os.getenv('TEXT_ALIGN', 'right')
def on_connect(client, userdata, flags, rc):
if rc == 0:
logger.info("Connected to MQTT Broker!")
else:
logger.error("Failed to connect, return code %d\n", rc)
if is_mqtt:
client = mqtt.Client()
if mqtt_username and mqtt_password:
client.username_pw_set(mqtt_username, mqtt_password)
logger.debug("Setting username and password")
client.on_connect = on_connect
logger.debug("Connecting to MQTT Broker")
client.connect(mqtt_broker, mqtt_port, 60)
client.loop_start()
# Icon mapping from API's "icon" field # Icon mapping from API's "icon" field
ICON_MAPPING = { ICON_MAPPING = {
@ -67,16 +95,19 @@ def send_post(endpoint,payload = {}, data = {}):
'accept': 'application/json', 'accept': 'application/json',
} }
uri = (FLIPDOT_API+endpoint).replace('\r', '').replace('\n', '') uri = (FLIPDOT_API+endpoint).replace('\r', '').replace('\n', '')
print(uri)
requests.post( uri, headers=headers, json = payload, params=data ) requests.post( uri, headers=headers, json = payload, params=data )
# Helper function to map API's icon to your icon set # Helper function to map API's icon to your icon set
def get_icon(api_icon): def get_icon(api_icon):
return ICON_MAPPING.get(api_icon, ICON_MAPPING["unknown"]) return ICON_MAPPING.get(api_icon, ICON_MAPPING["unknown"])
def fetch_luftdaten_data(): # def fetch_luftdaten_data():
url = "https://data.sensor.community/airrohr/v1/sensor/{}/".format(LUFTDATEN_CLOSEST_SENSOR).replace('\r', '').replace('\n', '') # url = "https://data.sensor.community/airrohr/v1/sensor/{}/".format(LUFTDATEN_CLOSEST_SENSOR).replace('\r', '').replace('\n', '')
response = requests.get(url) # try:
return response.json() # response = requests.get(url, timeout=5)
# except requests.exceptions.Timeout:
# logger.error("Request to Luftdaten API timed out")
# response = {"sensordatavalues": [{"value": "N/A"}, {"value": "N/A"}]}
# return response.json()
# Fetch current weather # Fetch current weather
def fetch_current_weather(): def fetch_current_weather():
@ -128,8 +159,8 @@ def generate_payload(current_weather, forecast):
weather_main = current_weather["weather"][0]["main"] weather_main = current_weather["weather"][0]["main"]
wind_speed = round(current_weather["wind"]["speed"] * 3.6) # Convert m/s to km/h wind_speed = round(current_weather["wind"]["speed"] * 3.6) # Convert m/s to km/h
wind_dir = current_weather["wind"]["deg"] wind_dir = current_weather["wind"]["deg"]
pm25 = fetch_luftdaten_data()[0]['sensordatavalues'][0]['value'] # pm25 = fetch_luftdaten_data()[0]['sensordatavalues'][0]['value']
pm10 = fetch_luftdaten_data()[0]['sensordatavalues'][1]['value'] # pm10 = fetch_luftdaten_data()[0]['sensordatavalues'][1]['value']
if "rain" in current_weather.keys(): if "rain" in current_weather.keys():
rain = current_weather["rain"]["1h"] rain = current_weather["rain"]["1h"]
@ -142,14 +173,14 @@ def generate_payload(current_weather, forecast):
snow = 0 snow = 0
payloads.append(create_payload(get_icon(weather_icon), f"NOW: {temp} st.C - {weather_main}", f"WIND: {wind_speed}KM/H {wind_dir}°")) payloads.append(create_payload(get_icon(weather_icon), f"NOW: {temp} st.C - {weather_main}", f"WIND: {wind_speed}KM/H {wind_dir}°"))
payloads.append(create_payload("mist", f"PM2.5: {pm25} ug/m3", f"PM10: {pm10} ug/m3")) # payloads.append(create_payload("mist", f"PM2.5: {pm25} ug/m3", f"PM10: {pm10} ug/m3"))
if rain > 0: if rain > 0:
payloads.append(create_payload("rain2", f"NOW: RAIN: {rain} mm", "IN 3H")) payloads.append(create_payload("rain2", f"NOW: RAIN: {rain} mm", "IN 3H"))
if snow > 0: if snow > 0:
payloads.append(create_payload("snow", f"NOW: SNOW: {snow} mm", "IN 3H")) payloads.append(create_payload("snow", f"NOW: SNOW: {snow} mm", "IN 3H"))
payloads.append(create_payload('mist', f"PM2.5: {pm25} ug/m3", f"PM10: {pm10} ug/m3")) # payloads.append(create_payload('mist', f"PM2.5: {pm25} ug/m3", f"PM10: {pm10} ug/m3"))
# Hourly forecast payloads # Hourly forecast payloads
for entry in forecast["list"][:DAYS]: for entry in forecast["list"][:DAYS]:
@ -170,18 +201,31 @@ def generate_payload(current_weather, forecast):
if snow > 0: if snow > 0:
payloads.append(create_payload("snow", f"{dt}: SNOW: {snow} mm", "IN 3H")) payloads.append(create_payload("snow", f"{dt}: SNOW: {snow} mm", "IN 3H"))
return evenly_distribute(payloads, FLIPDOT_SLOTS)
return payloads if not even_distribution else evenly_distribute(payloads,FLIPDOT_SLOTS)
def send_mqtt(page, payload):
topic = f"{mqtt_topic_base}/{page}"
client.publish(topic, json.dumps(payload))
# Main function # Main function
def main(): def main():
current_weather = fetch_current_weather() current_weather = fetch_current_weather()
forecast = fetch_hourly_forecast() forecast = fetch_hourly_forecast()
payloads = generate_payload(current_weather, forecast) payloads = generate_payload(current_weather, forecast, font=text_font, align=text_align)
clean() if is_post:
clean()
for i, payload in enumerate(payloads): for i, payload in enumerate(payloads):
logger.debug(payload) logger.debug(payload)
logger.info(f"Sending frame {i+1} of {len(payloads)} - text: {payload['lines'][0]['text']}") logger.info(f"Sending frame {i+1} of {len(payloads)} - text: {payload['lines'][0]['text']}")
send_post('display/complex', payload=payload,data={'page':i}) if is_post:
send_post(payload['endpoint'], data={'page':i},payload=payload)
logger.info("Sending payload via POST request")
if is_mqtt:
send_mqtt(i, payload)
logger.info("Sending payload via MQTT")
logger.info("Text: {}".format(payload['lines'][0]['text']))
logger.info("Text: {}".format(payload['lines'][1]['text']))
if __name__ == "__main__": if __name__ == "__main__":
main() main()

19
apply_env.sh Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# Check if the .env file exists
if [ ! -f .env ]; then
echo ".env file not found!"
exit 1
fi
# Read the .env file line by line
while IFS='=' read -r key value; do
# Skip empty lines or comments
if [[ -z "$key" || "$key" =~ ^# ]]; then
continue
fi
# Export the variable
echo "Setting $key as $value"
export "$key=$value"
done < .env

View File

@ -1,3 +1,4 @@
requests requests
urllib3 urllib3
python-dotenv python-dotenv
paho-mqtt