From 8a686abf22ea441d69827b20fd8947dffe18a91c Mon Sep 17 00:00:00 2001 From: Daithi Hearn Date: Sat, 15 Apr 2023 20:12:55 +0200 Subject: [PATCH] Adding build stuff --- .github/workflows/build-docker-image.yml | 16 +++ .github/workflows/publish-to-dockerhub.yml | 29 ++++++ Dockerfile | 14 +++ Electricity.py | 111 ++++++++++----------- docker-compose.yaml | 10 ++ requirements.txt | 3 +- 6 files changed, 123 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/build-docker-image.yml create mode 100644 .github/workflows/publish-to-dockerhub.yml create mode 100644 Dockerfile create mode 100644 docker-compose.yaml diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml new file mode 100644 index 0000000..986cac1 --- /dev/null +++ b/.github/workflows/build-docker-image.yml @@ -0,0 +1,16 @@ +name: Build Docker image + +on: + workflow_dispatch: + pull_request: + branches: ["main"] + +jobs: + build: + name: Build docker image + runs-on: self-hosted + + steps: + - uses: actions/checkout@v3 + - name: Build the Docker image + run: docker build . --file Dockerfile diff --git a/.github/workflows/publish-to-dockerhub.yml b/.github/workflows/publish-to-dockerhub.yml new file mode 100644 index 0000000..f91d095 --- /dev/null +++ b/.github/workflows/publish-to-dockerhub.yml @@ -0,0 +1,29 @@ +name: Publish to Dockerhub + +on: + release: + types: [published] + +jobs: + publish: + name: Build and Publish docker image to dockerhub + permissions: + contents: write + pull-requests: write + packages: read + runs-on: self-hosted + + steps: + - uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Publish to Registry + uses: elgohr/Publish-Docker-Github-Action@v5 + with: + name: daithihearn/electricity-prices-dashboard + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + platforms: linux/amd64,linux/arm64/v8 + tags: "latest,${{ github.ref_name }}" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a5315f1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.11.3 + +# Set the working directory to /app +WORKDIR /app + +# Install dependencies +COPY requirements.txt /app +RUN pip install --trusted-host pypi.python.org -r requirements.txt + +# Copy source code +COPY . /app + +# Run the app +CMD ["streamlit", "run", "Electricity.py"] diff --git a/Electricity.py b/Electricity.py index 8226fe2..980226e 100644 --- a/Electricity.py +++ b/Electricity.py @@ -1,28 +1,19 @@ import streamlit as st -import time -import os -import logging import requests -import numpy as np import pandas as pd import json from babel.numbers import format_decimal from datetime import date, datetime, timedelta from dateutil.parser import parse -from dotenv import load_dotenv -from streamlit_timeline import st_timeline st.set_page_config(layout="wide") - - def format_euro(amount) -> str: return f'{format_decimal(amount, locale="en_GB", format="#,##0.000")}' -PRICES_API= 'https://elec.daithiapp.com/api/v1/price' - +PRICES_API = 'https://elec.daithiapp.com/api/v1/price' class Price: @@ -45,25 +36,26 @@ def get_prices(start: date, end: date) -> list[Price]: return [Price(x.get('price'), parse(x.get('dateTime'))) for x in price_data] - def get_current_price(prices: list[Price]) -> Price: now = datetime.now() hour = now.strftime('%H') return next((x for x in prices if x.datetime.strftime('%H') == hour), None) + def get_tomorrow(): today = date.today() tomorrow = today + timedelta(days=1) return get_prices(tomorrow, tomorrow) + def get_today(): today = date.today() return get_prices(today, today) -def get_date_days_ago(days:int): - ago=date.today() - timedelta(days=days) - return get_prices(ago, ago) +def get_date_days_ago(days: int): + ago = date.today() - timedelta(days=days) + return get_prices(ago, ago) def get_min_price(prices: list[Price]): @@ -74,8 +66,6 @@ def get_max_price(prices: list[Price]): return max(prices, key=lambda x: x.value) - - def get_cheapest_period(prices: list[Price], n: int): prices_sorted = sorted(prices, key=lambda x: x.hour) @@ -90,6 +80,7 @@ def get_cheapest_period(prices: list[Price], n: int): return min_window + def get_cheap_period_recent_average(days: int) -> float: today = date.today() @@ -104,81 +95,83 @@ def get_cheap_period_recent_average(days: int) -> float: return total / days + def calculate_average(prices: list[Price]) -> float: return sum(x.value for x in prices) / len(prices) - -#get data +# get data # price_data_v1=get_prices() - st.title('Electricity prices') start_date_average = date.today() - timedelta(days=30) -elecAverage= round(calculate_average(get_prices ( start_date_average,date.today())),2) -currentPrice=round(get_current_price(get_today()).value,2) -difElec=round(currentPrice - elecAverage,2) +elecAverage = round(calculate_average( + get_prices(start_date_average, date.today())), 2) +currentPrice = round(get_current_price(get_today()).value, 2) +difElec = round(currentPrice - elecAverage, 2) col1, col2, col3, col4 = st.columns(4) -col1.metric("Average Price (30 days)" , elecAverage,delta_color="inverse") -col2.metric("Current Price" , currentPrice,difElec,delta_color="inverse") -labelminhour= "Min Price at " +get_min_price(get_today()).hour + ":00" -labelmaxhour= "Max Price at " +get_max_price(get_today()).hour + ":00" - -minToday=round(get_min_price(get_today()).value,2) -difElecMin=round(minToday - elecAverage,2) +col1.metric("Average Price (30 days)", elecAverage, delta_color="inverse") +col2.metric("Current Price", currentPrice, difElec, delta_color="inverse") +labelminhour = "Min Price at " + get_min_price(get_today()).hour + ":00" +labelmaxhour = "Max Price at " + get_max_price(get_today()).hour + ":00" -maxToday=round(get_max_price(get_today()).value,2) -difElecMax=round(maxToday - elecAverage,2) +minToday = round(get_min_price(get_today()).value, 2) +difElecMin = round(minToday - elecAverage, 2) -col3.metric(labelminhour, minToday,difElecMin,delta_color="inverse") -col4.metric(labelmaxhour, maxToday,difElecMax,delta_color="inverse") +maxToday = round(get_max_price(get_today()).value, 2) +difElecMax = round(maxToday - elecAverage, 2) +col3.metric(labelminhour, minToday, difElecMin, delta_color="inverse") +col4.metric(labelmaxhour, maxToday, difElecMax, delta_color="inverse") -if get_tomorrow(): +if get_tomorrow(): st.write('TOMORROW') - labelminhourT= "Min Price at " + get_min_price(get_tomorrow()).hour + ":00" - labelmaxhourT= "Max Price at " +get_max_price(get_tomorrow()).hour + ":00" - + labelminhourT = "Min Price at " + \ + get_min_price(get_tomorrow()).hour + ":00" + labelmaxhourT = "Max Price at " + \ + get_max_price(get_tomorrow()).hour + ":00" col1, col2, col3 = st.columns(3) - col2.metric(labelminhourT, round(get_min_price(get_tomorrow()).value,2),delta_color="inverse") - col3.metric(labelmaxhourT, round(get_max_price(get_tomorrow()).value,2),delta_color="inverse") + col2.metric(labelminhourT, round(get_min_price( + get_tomorrow()).value, 2), delta_color="inverse") + col3.metric(labelmaxhourT, round(get_max_price( + get_tomorrow()).value, 2), delta_color="inverse") else: - st.subheader("Tomorrow's prices are not available yet") + st.subheader("Tomorrow's prices are not available yet") st.header("Last 30 days evolutions") -#Plot timeline -ago_days=30 -i=0; +# Plot timeline +ago_days = 30 +i = 0 # initialize list for plot date_arr = [] -avg_arr=[] +avg_arr = [] for x in range(ago_days, 0, -1): - i=i+1 + i = i+1 date_average = date.today() - timedelta(x) date_average_str = str(date.today() - timedelta(x)) - average_str=str( round(calculate_average(get_date_days_ago(x)),2)) - average=round(calculate_average(get_date_days_ago(x)),2) + average_str = str(round(calculate_average(get_date_days_ago(x)), 2)) + average = round(calculate_average(get_date_days_ago(x)), 2) date_arr.append(date_average_str) avg_arr.append(average) df = pd.DataFrame({ - 'date': date_arr, - 'Average electricity prices': avg_arr + 'date': date_arr, + 'Average electricity prices': avg_arr }) -df = df.rename(columns={'date':'index'}).set_index('index') +df = df.rename(columns={'date': 'index'}).set_index('index') # Create the pandas DataFrame - #dateList.append( {"id": str(i), "content": "100", "start": "100"}) - #st.write(calculate_average(get_date_days_ago(x))) - -chart= st.line_chart(df) -#timeline = st_timeline(dateList, groups=[], options={}, height="300px") +# dateList.append( {"id": str(i), "content": "100", "start": "100"}) +# st.write(calculate_average(get_date_days_ago(x))) + +chart = st.line_chart(df) +# timeline = st_timeline(dateList, groups=[], options={}, height="300px") # start_day = '2023-03-01' @@ -196,8 +189,8 @@ def calculate_average(prices: list[Price]) -> float: # for x in price_data: # new_rows = [x.get('price'), x.get('dateTime')] # #status_text.text("%x%% Complete" % x) -# chart.add_rows(new_rows) - +# chart.add_rows(new_rows) + # # progress_bar.progress(x) # #last_rows = new_rows # time.sleep(0.000005) @@ -211,9 +204,9 @@ def calculate_average(prices: list[Price]) -> float: # last_rows = new_rows # time.sleep(0.05) -#progress_bar.empty() +# progress_bar.empty() # Streamlit widgets automatically run the script from top to bottom. Since # this button is not connected to any other logic, it just causes a plain # rerun. -#st.button("Re-run") \ No newline at end of file +# st.button("Re-run") diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..b5e892b --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,10 @@ +version: "3.5" + +services: + + electricity-prices-dashboard: + image: electricity-prices-dashboard + container_name: electricity-prices-dashboard + restart: always + ports: + - 8501:8501 diff --git a/requirements.txt b/requirements.txt index 2aa78fd..c14cca9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ babel +streamlit python-dotenv asyncio meross_iot==0.4.5.9 python-i18n[YAML] -python-dateutil \ No newline at end of file +python-dateutil