pufferfish-tech / octopus-agile-pi-prices

Display the upcoming prices on the Octopus Energy "Agile" tariff.
Apache License 2.0
71 stars 27 forks source link

support for a 3.5 inch display. #25

Open GamingDaveUk opened 7 months ago

GamingDaveUk commented 7 months ago

Is your feature request related to a problem? Please describe. I just purchased a 3.5inch display for a pi 2 model b to display the curerent half hour rate - upcoming rate - current consumption (if the api supports it) - consumption so far on that day (and price....) The idea was to replace my smart meters out of date monitor that cant show anything beyond current consumption lol

Then I realised I dont know how to do any of that and google lead me here.

Describe the solution you'd like I would love to be able to display the text like you have it but on a self updating local website hosted on the PI, displayed on the 3.5 inch display. Not sure if such is possible.

Describe alternatives you've considered sitting in the corner and rocking back and forward slowly. learning python and how to make a website thats dynamic using python...thats actually a long term thing. Additional context I know c#, would be happy to be shown how to get a specific value for the half hour time slot via the api and have it in a variable then pointed in the direction of how to make a website with python that displays that variable on it.... armed with that knowledge i could probably extrapolate the rest.... but i dont know where to begin lol

Your app fills a mysql database, so knowing how to pull a value from that data base and a link to a good noob friendly python website building guide could be all I need?

GamingDaveUk commented 7 months ago

Not one to sit idle and wait for solutions to land on my lap i set about working out how to do this. Aided massively (and hindered by) ChatGPT.

I broke the problem down into several parts. I needed the site to autoupdate on recieving new data (as the site is what will be on my display) and i needed a way to parse the data from the api curl grab.

The scripts are stored in a folder and the webpage is stored in a templates folder in that folder... it makes sense when you look at the code.

The website: `<!DOCTYPE html>

Rate Update

Current rate:

Next rate:

`

The server.py (this needs to be running all the time. `from flask import Flask, render_template from flask_socketio import SocketIO, emit

app = Flask(name) socketio = SocketIO(app, async_mode='eventlet')

current_rate = "Initial Current Rate" next_rate = "Initial Next Rate"

@app.route('/') def index(): return render_template('index.html', current_rate=current_rate, next_rate=next_rate)

Modify the 'update_rates' event to 'update' in server.py

@socketio.on('update_rates') def handle_update_rates(data): global current_rate, next_rate current_rate = data['current_rate'] next_rate = data['next_rate'] emit('update', {'current_rate': current_rate, 'next_rate': next_rate}, broadcast=True) print('Emitted update event:', {'current_rate': 99, 'next_rate': 88})

if name == 'main': socketio.run(app, debug=True, host='0.0.0.0')

@socketio.on('connect') def handle_connect(): print('Client connected')

@sio.on('disconnect') def on_disconnect(): print('Disconnected from server') `

The client.py... this is what i plan to run via cron every 30 minutes. `import socketio import time import json from datetime import datetime, timedelta

sio = socketio.Client() json_file_path = 'data.json' current_datetime = datetime.now()

@sio.on('connect')

def on_connect(): print('Connected to server')

def get_current_value_inc_vat(json_file_path):

Load JSON data from the file

with open(json_file_path, 'r') as file:
    data = json.load(file)

# Get the current date and time
#current_datetime = datetime.now()

# Iterate through the "results" list to find the corresponding "value_inc_vat"
for result in data['results']:
    valid_from = datetime.strptime(result['valid_from'], "%Y-%m-%dT%H:%M:%SZ")
    valid_to = datetime.strptime(result['valid_to'], "%Y-%m-%dT%H:%M:%SZ")

    # Check if the current time is within the valid range
    if valid_from <= current_datetime <= valid_to:
        return result['value_inc_vat']

# If no matching time range is found, return None or an appropriate value
return None

def get_value_at_future_time(json_file_path, minutes_offset=0):

Load JSON data from the file

with open(json_file_path, 'r') as file:
    data = json.load(file)

# Get the current date and time
#current_datetime = datetime.now()

# Calculate the future time by adding the specified offset (in minutes)
future_datetime = current_datetime + timedelta(minutes=minutes_offset)
    # Iterate through the "results" list to find the corresponding value at the future time
for result in data['results']:
    valid_from = datetime.strptime(result['valid_from'], "%Y-%m-%dT%H:%M:%SZ")
    valid_to = datetime.strptime(result['valid_to'], "%Y-%m-%dT%H:%M:%SZ")

    # Check if the future time is within the valid range
    if valid_from <= future_datetime <= valid_to:
        return result['value_inc_vat']

# If no matching time range is found, return None or an appropriate value
return None

def update_rates(current_rate, next_rate): sio.emit('update_rates', {'current_rate': current_rate, 'next_rate': next_rate}) print('Sent update_rates event to server') print(f"current rate: {current_rate} - next rate: {next_rate}")

if name == 'main': try: sio.connect('http://localhost:5000') # Adjust the server URL as needed

    # Update the rates here
    current_rate = get_current_value_inc_vat(json_file_path)
    next_rate = get_value_at_future_time(json_file_path, minutes_offset=30)

    # Send the updated rates to the server
    update_rates(current_rate, next_rate)

except KeyboardInterrupt:
    print("Client closed by the user.")

`

The data.json is in the same folder as the scripts and contains the out put of the curl command to get the rates. bit too long to add here but its the result of the curl command from Unit rates on https://octopus.energy/dashboard/new/accounts/personal-details/api-access

I still need to write a script that will run that curl command at 1600 and replace the existing data.json file...but i feel that should be simple enough. There are also a lot of pip install modules that are needed for this which i didnt document. posting this as i hate leaving a question with "done" or "fixed it" I doubt me and chatgpt came up with the best way... but it works.... most of the time....it did seem to strugle to update the site then suddenly it updated it, The web page needs to be full screened on the tft display and I likely need to find some code to move the text about to prevent burn in.

I initially tried to host the page seperate from the script but that proved to be a pain from a sockets point of view. I havent looked at pulling current usage or the daily consumption yet, not sure thats possible with the api. Interesting experiement though and something i plan to look more at with time

EDIT: i put the files in code togs for github...it doesnt seem to have liked that. but anyone trying to repeat what i did should be able to decode these lol

GamingDaveUk commented 7 months ago

I wasnt happy with how the text got mangled above so I created a repo for what I was doing. This includes the .sh for retrieving the prices too no readme yet, I need to have some time to write that. https://github.com/GamingDaveUk/OctopusAgileRatePage

I have no idea if this is even remotely helpful to others though lol