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

Feat/build args #568

Merged
merged 2 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 150 additions & 135 deletions poetry.lock

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,16 @@ websocket-client = "^1.7.0"
sqlalchemy = "^1.0.0"
fastapi-utils = "^0.2.1"
pytz = "^2023.3.post1"
opentelemetry-distro = "^0.46b0"
opentelemetry-exporter-otlp = "^1.25.0"
opentelemetry-instrumentation-requests = "^0.46b0"
opentelemetry-instrumentation-fastapi = "^0.46b0"
opentelemetry-instrumentation-sqlalchemy = "^0.46b0"
opentelemetry-distro = ">0.46b0"
opentelemetry-exporter-otlp = ">1.25.0"
opentelemetry-instrumentation-requests = ">0.46b0"
opentelemetry-instrumentation-fastapi = ">0.46b0"
opentelemetry-instrumentation-sqlalchemy = ">0.46b0"
ruamel-yaml = "^0.18.6"
unidecode = "^1.3.8"
deepdiff = "^7.0.1"
setuptools = ">72.0.0"
fastapi-lifespan-manager = "^0.1.4"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.4"
Expand Down
23 changes: 19 additions & 4 deletions src/config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import sys
from os import getenv
from typing import List

from deepdiff import DeepDiff
from opentelemetry import trace
Expand All @@ -25,7 +26,8 @@
from config.optel import OpTel
from config.server import Server
from const import URL_CONFIG_FILE
from utils import edit_config, load_config, logo, str2bool, title
from database.usage_points import DatabaseUsagePoints
from utils import barcode_message, edit_config, load_config, logo, str2bool, title

locale.setlocale(locale.LC_ALL, "fr_FR.UTF-8")

Expand Down Expand Up @@ -88,7 +90,6 @@ def __init__(self):
self.load_logging()
self.setup_tracing()
logo(VERSION)
self.display()

comments = None
for key in self.config.config:
Expand All @@ -99,6 +100,7 @@ def __init__(self):

self.check_config()
if self.dev:
barcode_message("DEV MODE")
exemple_file = "config.example.yaml"
edit_config(data=self.default, file=exemple_file, comments=comments, wipe=True)
edit_config(
Expand All @@ -108,6 +110,19 @@ def __init__(self):
wipe=True,
)
title([f"Generate {exemple_file}", f" => {exemple_file} generated"])
self.display()
self.clean_database()

def clean_database(self):
"""Clean database."""
title("Nettoyage de la base de données...")
usage_point_list: List[UsagePointId] = []
if self.myelectricaldata.usage_point_config is not None:
for upi, _ in self.myelectricaldata.usage_point_config.items():
usage_point_list.append(upi)
for usage_point in DatabaseUsagePoints().get_all():
if usage_point.usage_point_id not in usage_point_list:
DatabaseUsagePoints(usage_point.usage_point_id).delete()

def check_config(self):
"""Check current config file."""
Expand Down Expand Up @@ -290,5 +305,5 @@ def tracing_fastapi(self, app):
logging.debug("[OpenTelemetry] FastAPI loaded")
FastAPIInstrumentor.instrument_app(app)


APP_CONFIG = Config()
if __name__ == "config.main":
APP_CONFIG = Config()
3 changes: 2 additions & 1 deletion src/database/usage_points.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Manage UsagePoints table in database."""

from datetime import datetime, timedelta
from typing import List

from sqlalchemy import delete, select, update
from sqlalchemy.orm import scoped_session
Expand Down Expand Up @@ -72,7 +73,7 @@ def __init__(self, usage_point_id=None):
self.session: scoped_session = DB.session()
self.usage_point_config = None

def get_all(self):
def get_all(self) -> List[UsagePoints]:
"""Get all data from usage point table."""
query = select(UsagePoints)
data = self.session.scalars(query).all()
Expand Down
22 changes: 14 additions & 8 deletions src/external_services/myelectricaldata/tempo.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Tempo:
def __init__(self):
self.url = URL
self.valid_date = datetime.combine(datetime.now(tz=TIMEZONE) + relativedelta(days=1), datetime.min.time())
self.display_nb_day = 10
self.nb_check_day = 31
self.total_tempo_days = {
"red": 22,
Expand All @@ -44,7 +45,7 @@ def run(self):
query_response = Query(endpoint=target).get()
if query_response.status_code == CODE_200_SUCCESS:
try:
response_json = json.loads(query_response.text)
response_json: dict = json.loads(query_response.text)
for date, color in response_json.items():
date_obj = datetime.strptime(date, "%Y-%m-%d").replace(tzinfo=TIMEZONE)
DatabaseTempo().set(date_obj, color)
Expand All @@ -57,11 +58,10 @@ def run(self):
"description": "Erreur lors de la récupération de données Tempo.",
}
return response
else:
return {
"error": True,
"description": json.loads(query_response.text)["detail"],
}
return {
"error": True,
"description": json.loads(query_response.text)["detail"],
}

def get(self):
"""Retrieves tempo data from the database.
Expand Down Expand Up @@ -110,8 +110,13 @@ def fetch(self):
else:
logging.info(" => Toutes les données sont déjà en cache.")
if "error" not in result:
for key, value in result.items():
logging.info(f"{key}: {value}")
if len(result) > 0:
i = 0
for key, value in result.items():
if i < self.display_nb_day:
logging.info(f"{key}: {value}")
i += 1
logging.info("...")
else:
logging.error(result)
return "OK"
Expand Down Expand Up @@ -140,6 +145,7 @@ def calc_day(self):
for day in current_tempo_day:
result[day.color.lower()] -= 1
DatabaseTempo().set_config("days", result)
logging.info(" => OK")
return result

def fetch_day(self):
Expand Down
96 changes: 45 additions & 51 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Main module of the application."""

from contextlib import asynccontextmanager
from os import listdir
from pathlib import Path

Expand All @@ -10,26 +11,38 @@
from uvicorn.config import LOGGING_CONFIG

from config.main import APP_CONFIG
from database.usage_points import DatabaseUsagePoints
from models.jobs import Job
from routers import account, action, data, html, info
from utils import get_version, title
from utils import get_version

usage_point_list = []
if APP_CONFIG.myelectricaldata.usage_point_config is not None:
for upi, _ in APP_CONFIG.myelectricaldata.usage_point_config.items():
usage_point_list.append(upi)

title("Nettoyage de la base de données...")
for usage_point in DatabaseUsagePoints().get_all():
if usage_point.usage_point_id not in usage_point_list:
DatabaseUsagePoints(usage_point.usage_point_id).delete()
#######################################################################################################################
# JOBS
@repeat_every(seconds=APP_CONFIG.server.cycle, wait_first=False)
def job_boot():
"""Bootstap jobs."""
Job().boot()


@repeat_every(seconds=3600, wait_first=True)
def job_home_assistant():
"""Home Assistant Ecowatt."""
Job().export_home_assistant(target="ecowatt")

swagger_configuration = {
"operationsSorter": "method",
"tagsSorter": "alpha",
"deepLinking": True,
}

@repeat_every(seconds=600, wait_first=False)
def job_gateway_status():
"""Gateway status check."""
Job().get_gateway_status()


@asynccontextmanager
async def bootstrap(app: FastAPI): # pylint: disable=unused-argument
"""Bootstap jobs."""
await job_boot()
await job_home_assistant()
await job_gateway_status()
yield


APP = FastAPI(
Expand All @@ -49,6 +62,7 @@
"tagsSorter": "alpha",
"deepLinking": True,
},
lifespan=bootstrap,
)

#######################################################################################################################
Expand All @@ -67,30 +81,6 @@
APP.include_router(action.ROUTER)
APP.include_router(account.ROUTER)


#######################################################################################################################
# JOB TASKS
@APP.on_event("startup")
@repeat_every(seconds=APP_CONFIG.server.cycle, wait_first=False)
def import_job():
"""Perform the import job."""
Job().boot()


@APP.on_event("startup")
@repeat_every(seconds=3600, wait_first=True)
def home_assistant_export():
"""Perform the home assistant export job."""
Job().export_home_assistant(target="ecowatt")


@APP.on_event("startup")
@repeat_every(seconds=600, wait_first=False)
def gateway_status():
"""Perform gateway status."""
Job().get_gateway_status()


#######################################################################################################################
# FastAPI opentelemetry configuration
APP_CONFIG.tracing_fastapi(APP)
Expand All @@ -103,19 +93,23 @@ def gateway_status():
log_config["formatters"]["access"]["datefmt"] = APP_CONFIG.logging.log_format_date
log_config["formatters"]["default"]["fmt"] = APP_CONFIG.logging.log_format
log_config["formatters"]["default"]["datefmt"] = APP_CONFIG.logging.log_format_date
uvicorn_params = {}
uvicorn_params["log_config"] = log_config
uvicorn_params["host"] = APP_CONFIG.server.cidr
uvicorn_params["port"] = APP_CONFIG.server.port
uvicorn_params["reload"] = True
uvicorn_params["reload_dirs"] = [APP_CONFIG.application_path]
uvicorn_params["reload_includes"] = [APP_CONFIG.application_path]
uvicorn_params["reload_excludes"] = [".venv", ".git/*", ".idea/*", ".vscode/*", ".py[cod]"]
uvicorn_params = {
"reload": False,
"log_config": log_config,
"host": APP_CONFIG.server.cidr,
"port": APP_CONFIG.server.port,
"log_level": "error",
"reload_dirs": None,
"reload_includes": None,
"reload_excludes": None,
}
if APP_CONFIG.logging.log_http:
uvicorn_params["log_level"] = "info"
else:
uvicorn_params["log_level"] = "error"
uvicorn_params = {**uvicorn_params, **APP_CONFIG.ssl_config.__dict__}
if APP_CONFIG.dev:
uvicorn_params["reload"] = True
uvicorn_params["reload_dirs"] = [APP_CONFIG.application_path]
uvicorn_params["reload_includes"] = [APP_CONFIG.application_path]
uvicorn_params["reload_excludes"] = [".venv", ".git/*", ".idea/*", ".vscode/*", ".py[cod]"]

APP_CONFIG.display()
uvicorn_params = {**uvicorn_params, **APP_CONFIG.ssl_config.__dict__}
uvicorn.run("main:APP", **uvicorn_params)
7 changes: 2 additions & 5 deletions src/models/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ def __init__(self, usage_point_id=None):

def boot(self):
"""Boots the import job."""
if APP_CONFIG.dev or APP_CONFIG.logging.debug:
if APP_CONFIG.dev:
logging.warning("=> Import job disable")
else:
self.job_import_data()

def job_import_data(self, wait=True, target=None): # noqa: PLR0912, PLR0915, C901
def job_import_data(self, wait=True, target=None): # noqa: PLR0912, C901
"""Import data from the API."""
if DB.lock_status():
return {"status": False, "notif": "Importation déjà en cours..."}
Expand All @@ -59,9 +59,6 @@ def job_import_data(self, wait=True, target=None): # noqa: PLR0912, PLR0915, C9
time.sleep(1)
i = i - 1

if target == "gateway_status" or target is None:
self.get_gateway_status()

# ######################################################################################################
# FETCH TEMPO DATA
if target == "tempo" or target is None:
Expand Down
2 changes: 0 additions & 2 deletions src/models/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

import requests

from database.config import DatabaseConfig
from utils import str2bool
from config.main import APP_CONFIG


Expand Down
7 changes: 7 additions & 0 deletions src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@ def get_version():
return VERSION


def barcode_message(message):
"""Barcode message."""
art = text2art(message)
for line in art.splitlines():
logging.info(f'{decor("barcode1")}{line: ^93}{decor("barcode1", reverse=True)}')


def logo(version):
"""Print the logo of MyElectricalData with the version number.

Expand Down
Loading