solar_bot/solar_bot.py

116 lines
4.1 KiB
Python

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# https://github.com/karioja/vedirect
# https://github.com/halcy/Mastodon.py
# Command: python3 solar_bot.py --port /dev/ttyUSB0
import settings
import argparse, os, time, datetime
from vedirect import Vedirect
from mastodon import Mastodon
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.start()
# DB 1 is used as DB 0 is used by mastodon
import redis
r = redis.Redis(host='localhost', port=6379, db=1, decode_responses=True)
import logging
logging.basicConfig(encoding='utf-8', level=logging.INFO)
# This needs to be uncommented on first run and then commented out after that - obviously there is a better way to do this.
#Mastodon.create_app(
# 'pytooterapp',
# api_base_url = instance_url,
# to_file = 'pytooter_clientcrednew.secret'
#)
def mastodon_login():
mastodon = Mastodon(client_id = settings.access_client_id,)
mastodon.log_in(
settings.mastodon_user,
settings.mastodon_password,
to_file = settings.access_secret
)
def print_data_callback(packet):
r.set('batt_v', packet['V'])
r.set('main_current', packet['I'])
r.set('panel_voltage',packet['VPV'])
r.set('panel_power',packet['PPV'])
r.set('load_current',packet['IL'])
r.set('yield_today',packet['H20'])
r.set('max_power_today',packet['H21'])
r.set('yield_yesterday',packet['H22'])
r.set('max_power_yesterday',packet['H23'])
def get_shutdown():
fp = open('/run/systemd/shutdown/scheduled')
data = fp.readlines()
fp.close()
shutdown_date = data[0].split('=')[1].rstrip()
ts = int(shutdown_date) / 1000000
time_now = int(time.time())
shutdown_date = datetime.datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
time_to_shutdown = ts - time_now
time_to_date = datetime.datetime.utcfromtimestamp(time_to_shutdown).strftime('%H:%M:%S')
return shutdown_date, time_to_date
def send_toot():
logging.info('Preparing Toot')
try:
batt_v_V = int(r.get('batt_v')) / 1000
main_current = r.get('main_current')
panel_voltage = int(r.get('panel_voltage')) / 1000
panel_power = r.get('panel_power')
load_current = int(r.get('load_current')) / 1000
yield_today = int(r.get('yield_today')) / 1000
max_power_today = r.get('max_power_today')
load_power = load_current * batt_v_V
final_date, time_date = get_shutdown()
toot_to_send = 'Solarcene.community Power Data\nBattery Voltage: {}V\nBattery Current: {}mA\nPanel Voltage: {}V\nPanel Power: {}W\nLoad Current: {}A\nLoad Power: {}W\nYield Today: {}kWh\nMax Power Today: {}W\nUpdated every 60 minutes\n\nShutdown planned for {}UTC (in {})'.format(batt_v_V, main_current, panel_voltage, panel_power, load_current, load_power, yield_today, max_power_today, final_date, time_date)
logging.info(toot_to_send)
except:
logging.info('Failed to construct toot')
try:
mastodon = Mastodon(access_token = settings.access_secret, api_base_url = settings.instance_url)
mastodon.toot(toot_to_send)
except:
logging.info('Failed to send toot')
def start_toot():
logging.info('Sleeping for 60 seconds to allow mastodon to fully start')
time.sleep(60)
try:
final_date, time_date = get_shutdown()
mastodon = Mastodon(access_token = settings.access_secret, api_base_url = settings.instance_url)
mastodon.toot('System Online\n\nShutdown planned for: {}UTC (in {})'.format(final_date, time_date))
except:
logging.info('Failed to send toot')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Process VE.Direct protocol')
parser.add_argument('--port', help='Serial port')
parser.add_argument('--timeout', help='Serial port read timeout', type=int, default='60')
args = parser.parse_args()
scheduler.add_job(send_toot, trigger='cron', minute=1)
logging.info('Starting')
mastodon_login()
logging.info('Logged In')
os.system("shutdown -h 20:15")
start_toot()
ve = Vedirect(args.port, args.timeout)
ve.read_data_callback(print_data_callback)
logging.info('Exit')