Skip to content

Commit

Permalink
Standalone Predbat development (#1138)
Browse files Browse the repository at this point in the history
* Standalone Predbat development

* [pre-commit.ci lite] apply automatic fixes

* Basic stand-alone working

* [pre-commit.ci lite] apply automatic fixes

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
  • Loading branch information
springfall2008 and pre-commit-ci-lite[bot] authored May 25, 2024
1 parent 27346b5 commit b3cf371
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 12 deletions.
92 changes: 92 additions & 0 deletions apps/predbat/hass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import io
import yaml
import sys
import asyncio
import predbat
import time
from datetime import datetime, timedelta
import logging
import logging.config
from multiprocessing import Pool, cpu_count, set_start_method


async def main():
print("Starting Standalone Predbat")
try:
p_han = predbat.PredBat()
p_han.initialize()
except Exception as e:
print("Failed to start predbat {}".format(e))
return

# Runtime loop
print("Started Predbat run loop")
while True:
time.sleep(1)
p_han.timer_tick()


if __name__ == "__main__":
import hass as hass

print("Starting Predbat standalone")
set_start_method("fork")
asyncio.run(main())
sys.exit(0)


class Hass:
def log(self, msg):
message = "{}: {}\n".format(datetime.now(), msg)
self.logfile.write(message)
print(message, end="")

def create_task(self, task):
return asyncio.create_task(task)

def __init__(self):
"""
Start Predbat
"""
self.args = {}
self.run_list = []
self.tasks = []

self.logfile = open("predbat.log", "a")

# Open YAML file apps.yaml and read it
print("Loading apps.yaml")
with io.open("apps.yaml", "r") as stream:
try:
config = yaml.safe_load(stream)
self.args = config["pred_bat"]
except yaml.YAMLError as exc:
print(exc)
sys.exit(1)

if "ha_url" not in self.args:
print("Error: ha_url not found in apps.yaml")
sys.exit(1)
if "ha_key" not in self.args:
print("Error: ha_key not found in apps.yaml")
sys.exit(1)

def run_every(self, callback, next_time, run_every, **kwargs):
print("Run every triggered next time {} every {}".format(next_time, run_every))
self.run_list.append({"callback": callback, "next_time": next_time, "run_every": run_every, "kwargs": kwargs})
return True

def timer_tick(self):
now = datetime.now()
print("Timer tick at {}".format(now))
for task in self.tasks:
if task.done():
print("Task done")
self.tasks.remove(task)
for item in self.run_list:
if now > item["next_time"]:
print("Running callback next time {} and now is {}".format(item["next_time"], now))
self.tasks.append(self.create_task(item["callback"](None)))
while now > item["next_time"]:
item["next_time"] += item["run_every"]
print("Task completed next time {}".format(item["next_time"]))
25 changes: 13 additions & 12 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,29 @@
see Readme for information
"""


import copy
import os
import re
import time
import math
from datetime import datetime, timedelta

# fmt off
# pylint: disable=consider-using-f-string
# pylint: disable=line-too-long
# pylint: disable=attribute-defined-outside-init
from datetime import datetime, timedelta

import adbase as ad
import appdaemon.plugins.hass.hassapi as hass
# Import AppDaemon or our standalone wrapper
try:
import adbase as ad
import appdaemon.plugins.hass.hassapi as hass
except:
import hass as hass

import pytz
import requests
import yaml
from multiprocessing import Pool, cpu_count
from multiprocessing import Pool, cpu_count, set_start_method
import asyncio
import aiohttp
from aiohttp import web
Expand Down Expand Up @@ -2827,7 +2831,7 @@ def create_entity(self, entity_name, value, uom=None, device_class="None"):

entity_id = f"sensor.{prefix}_{self.inverter_type}_{self.id}_{entity_name}"

if not self.base.entity_exists(entity_id):
if self.base.get_state_wrapper(entity_id) is None:
attributes = {
"state_class": "measurement",
}
Expand Down Expand Up @@ -13928,7 +13932,6 @@ def update_time(self, print=True):
self.minutes_to_midnight = 24 * 60 - self.minutes_now
self.log("--------------- PredBat - update at {} with clock skew {} minutes, minutes now {}".format(now_utc, skew, self.minutes_now))

@ad.app_lock
def update_pred(self, scheduled=True):
"""
Update the prediction state, everything is called from here right now
Expand Down Expand Up @@ -15015,10 +15018,9 @@ def initialize(self):
run_every = RUN_EVERY * 60
now = self.now

self.ha_interface = HAInterface(self)

try:
self.reset()
self.ha_interface = HAInterface(self)
self.sanity()
self.ha_interface.update_states()
self.auto_config()
Expand Down Expand Up @@ -15088,7 +15090,6 @@ async def terminate(self):
self.pool = None
self.log("Predbat terminated")

@ad.app_lock
def update_time_loop(self, cb_args):
"""
Called every 15 seconds
Expand All @@ -15109,7 +15110,6 @@ def update_time_loop(self, cb_args):
self.prediction_started = False
self.prediction_started = False

@ad.app_lock
def run_time_loop(self, cb_args):
"""
Called every N minutes
Expand Down Expand Up @@ -15173,6 +15173,8 @@ def __init__(self, base):
else:
self.log("Info: Connected to Home Assistant at {}".format(self.ha_url))
self.base.create_task(self.socketLoop())
self.websocket_active = True
self.log("Info: Web Socket task started")

async def socketLoop(self):
"""
Expand Down Expand Up @@ -15202,7 +15204,6 @@ async def socketLoop(self):
sid += 1

self.log("Info: Web Socket active")
self.websocket_active = True

async for message in websocket:
if message.type == aiohttp.WSMsgType.TEXT:
Expand Down

0 comments on commit b3cf371

Please sign in to comment.