mqtt and other stuff to make it similar to departures generator
This commit is contained in:
parent
38b6726e39
commit
950c678492
12
.env.dist
12
.env.dist
|
@ -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
|
13
Dockerfile
13
Dockerfile
|
@ -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
72
app.py
|
@ -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()
|
||||||
|
|
|
@ -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
|
|
@ -1,3 +1,4 @@
|
||||||
requests
|
requests
|
||||||
urllib3
|
urllib3
|
||||||
python-dotenv
|
python-dotenv
|
||||||
|
paho-mqtt
|
Loading…
Reference in New Issue