Added minimal first version (#1)

Reviewed-on: https://git.cuzo.dev/Parra/crypto-reporter/pulls/1
This commit is contained in:
parra 2022-09-16 19:15:08 +02:00 committed by Parra
parent 821f55d31a
commit 0224e02f6a
7 changed files with 480 additions and 0 deletions

152
.drone.yml Normal file
View file

@ -0,0 +1,152 @@
kind: pipeline
type: docker
name: arm32
platform:
arch: arm
steps:
- name: Build arm/v7
image: registry.cuzo.dev/plugins/docker
privileged: true
settings:
repo: parrazam/crypto-reporter
auto_tag: true
auto_tag_suffix: linux-arm
mirror: https://registry.cuzo.dev
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
image_pull_secrets:
- PRIVATE_DOCKER_REGISTRY
trigger:
event:
- push
- tag
---
kind: pipeline
type: docker
name: amd64
platform:
arch: amd64
steps:
- name: Build amd64
image: registry.cuzo.dev/plugins/docker
privileged: true
volumes:
- name: manifest
path: docker
settings:
repo: parrazam/crypto-reporter
auto_tag: true
auto_tag_suffix: linux-amd64
mirror: https://registry.cuzo.dev
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
image_pull_secrets:
- PRIVATE_DOCKER_REGISTRY
trigger:
event:
- push
- tag
---
kind: pipeline
type: docker
name: manifest
steps:
- name: Upload manifest
image: registry.cuzo.dev/plugins/manifest
privileged: true
volumes:
- name: manifest
path: docker
settings:
target: parrazam/crypto-reporter
template: parrazam/crypto-reporter:OS-ARCH
auto_tag: true
ignore_missing: true
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
platforms:
- linux/amd64
- linux/arm
depends_on:
- amd64
- arm32
image_pull_secrets:
- PRIVATE_DOCKER_REGISTRY
trigger:
event:
- push
- tag
---
kind: pipeline
type: docker
name: release
steps:
- name: release
image: registry.cuzo.dev/plugins/gitea-release
settings:
api_key:
from_secret: DRONE_API_KEY
base_url: https://git.cuzo.dev
title:
from_secret: DRONE_SEMVER
when:
ref:
- refs/tags/*
depends_on:
- manifest
image_pull_secrets:
- PRIVATE_DOCKER_REGISTRY
trigger:
event:
- tag
---
kind: pipeline
type: docker
name: Notify result
steps:
- name: send telegram notification
image: registry.cuzo.dev/appleboy/drone-telegram
when:
status: [success, failure]
settings:
to:
from_secret: TG_USER
token:
from_secret: TG_TOKEN
depends_on:
- manifest
- release
image_pull_secrets:
- PRIVATE_DOCKER_REGISTRY
trigger:
event:
- push
- tag

162
.gitignore vendored Normal file
View file

@ -0,0 +1,162 @@
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

9
Dockerfile Normal file
View file

@ -0,0 +1,9 @@
FROM python:3-alpine
# Install dependencies:
COPY requirements.txt .
RUN pip install -r requirements.txt
# Run the application:
COPY main.py .
CMD ["python", "main.py"]

View file

@ -1 +1,45 @@
# crypto-reporter
[![Build Status](https://drone.cuzo.dev/api/badges/Parra/crypto-reporter/status.svg)](https://drone.cuzo.dev/Parra/crypto-reporter)
Obtiene y publica precios de criptomonedas.
## Instalación y ejecución desde CLI
Descargar el repositorio en una nueva carpeta:
````shell
git clone https://git.cuzo.dev/Parra/crypto-reporter.git
````
Copiar el fichero `env_file` a `.env` y abrirlo con un editor de textos y editarlo
con la información del servidor MQTT, así como editar los tópicos que se quieran usar
y el tiempo de refresco.
Dar permisos de ejecución al fichero principal con `chmod +x main.py` y ejecutar con `./main.py`.
## Instalación y ejecución desde Docker
Crear una carpeta (por ejemplo `crypto-reporter`) y acceder a ella.
Crear un fichero `.env` con el contenido del fichero `env_file` de este repositorio y
editarlo con la información del servidor MQTT.
Crear un fichero `docker-compose.yml` como el siguiente:
````yml
version: '3'
services:
crypto-reporter:
image: parrazam/crypto-reporter
container_name: crypto-reporter
restart: unless-stopped
volumes:
- ./.env:/.env:ro
````
Ejecutar con el comando `docker compose up -d`.
## Menciones
La API se extrae de Coingecko y se puede consultar aquí: https://www.coingecko.com/en/api/documentation

21
env_file Normal file
View file

@ -0,0 +1,21 @@
# Log configuration
LOG_LEVEL=INFO
# Crypto configuration
CRYPTOS_TO_PUBLISH=bitcoin,ethereum
CURRENCIES=eur,usd
# Broker configuration
MQTT_SERVER=
MQTT_PORT=
MQTT_USER=
MQTT_PASSWORD=
MQTT_CLIENT_ID=
# Topic configuration
MQTT_TOPIC_PREFIX=
MQTT_TOPIC_STATE=${MQTT_TOPIC_PREFIX}/state
MQTT_TOPIC_DATA=${MQTT_TOPIC_PREFIX}/data
MQTT_PUBLISH_DELAY=60

89
main.py Normal file
View file

@ -0,0 +1,89 @@
# !/usr/bin/env python3
"""Crypto reporter"""
import json
import logging
import os
import requests
import time
from dotenv import load_dotenv
import paho.mqtt.client as mqtt
load_dotenv() # Cargamos las variables de entorno necesarias
LOG_LEVEL = os.getenv('LOG_LEVEL', logging.INFO)
logging.basicConfig(level=LOG_LEVEL, format='[%(levelname)s] %(asctime)s - %(message)s')
BASE_API = 'https://api.coingecko.com/api/v3'
MQTT_TOPIC_DATA = os.getenv('MQTT_TOPIC_DATA', 'crypto-reporter/data')
MQTT_TOPIC_STATE = os.getenv('MQTT_TOPIC_STATE', 'crypto-reporter/state')
MQTT_PUBLISH_DELAY = int(os.getenv('MQTT_PUBLISH_DELAY', 60))
MQTT_CLIENT_ID = os.getenv('MQTT_CLIENT_ID', 'crypto-reporter')
MQTT_SERVER = os.getenv('MQTT_SERVER', 'localhost')
MQTT_PORT = int(os.getenv('MQTT_PORT', '1883'))
MQTT_USER = os.getenv('MQTT_USER', '')
MQTT_PASSWORD = os.getenv('MQTT_PASSWORD', '')
CRYPTOS_TO_PUBLISH = os.getenv('CRYPTOS_TO_PUBLISH', 'bitcoin')
CURRENCIES = os.getenv('CURRENCIES', 'eur')
def on_connect(client, userdata, flags, rc):
logging.info("Connected to MQTT server.")
client.publish(MQTT_TOPIC_STATE, 'connected', 1, True)
def main():
logging.info(f'Connecting to MQTT host {MQTT_SERVER}:{MQTT_PORT}...')
mqttc = mqtt.Client(MQTT_CLIENT_ID)
mqttc.username_pw_set(MQTT_USER, MQTT_PASSWORD)
mqttc.will_set(MQTT_TOPIC_STATE, 'disconnected', 1, True)
mqttc.on_connect = on_connect
mqttc.connect(MQTT_SERVER, MQTT_PORT, 60)
mqttc.loop_start()
last_msg_time = time.time()
while True:
try:
x = requests.get(BASE_API + '/simple/price',
params={'ids': CRYPTOS_TO_PUBLISH,
'vs_currencies': CURRENCIES})
logging.debug(f'HTTP response: {x.status_code}')
publish_data(mqttc, x.text)
delay_gap = time.time() - last_msg_time
if delay_gap < MQTT_PUBLISH_DELAY:
time.sleep(MQTT_PUBLISH_DELAY - delay_gap)
last_msg_time = time.time()
except KeyboardInterrupt:
logging.info("exiting...")
exit(0)
except Exception:
logging.exception("something went wrong.")
exit(1)
def publish_data(mqttc, raw):
try:
logging.debug(f'RAW message to publish: {raw}')
data = json.loads(raw)
for crypto in data:
currencies = data[crypto]
for currency in currencies:
mqttc.publish(MQTT_TOPIC_DATA + f'/{crypto}/{currency}', data[crypto][currency], 1, True)
except AttributeError:
logging.exception("Error decoding JSON")
if __name__ == '__main__':
logging.info('Starting crypto broker')
main()

3
requirements.txt Normal file
View file

@ -0,0 +1,3 @@
paho-mqtt==1.6.1
python-dotenv==0.21.0
requests==2.28.1