Merge branch 'development' into master

This commit is contained in:
pascal1404 2022-02-06 14:06:21 +01:00 committed by GitHub
commit 49e8488c0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 180 additions and 22 deletions

View file

@ -1,2 +1 @@
__version__ = "4.0.1.2" __version__ = "4.0.1.12"

View file

@ -51,10 +51,10 @@ class CBPiBase(metaclass=ABCMeta):
def get_actor_state(self,id): def get_actor_state(self,id):
try: try:
actor = self.cbpi.actor.find_by_id(id) actor = self.cbpi.actor.find_by_id(id)
return actor.get("instance").get_state() return actor.instance.state
except: except:
logging.error("Failed to read actor state in step - actor {}".format(id)) logging.error("Failed to read actor state in step - actor {}".format(id))
return None return False
async def actor_on(self,id,power=100): async def actor_on(self,id,power=100):
@ -73,4 +73,4 @@ class CBPiBase(metaclass=ABCMeta):
try: try:
await self.cbpi.actor.set_power(id,power) await self.cbpi.actor.set_power(id,power)
except Exception as e: except Exception as e:
pass pass

View file

@ -10,6 +10,7 @@ from cbpi.utils.utils import load_config
from zipfile import ZipFile from zipfile import ZipFile
from cbpi.craftbeerpi import CraftBeerPi from cbpi.craftbeerpi import CraftBeerPi
import os import os
import platform
import pathlib import pathlib
import shutil import shutil
import yaml import yaml
@ -152,14 +153,19 @@ def check_for_setup():
if zip_content == True: if zip_content == True:
print("Found correct content. Starting Restore process") print("Found correct content. Starting Restore process")
output_path = pathlib.Path(os.path.join(".", 'config')) output_path = pathlib.Path(os.path.join(".", 'config'))
owner = output_path.owner() system = platform.system()
group = output_path.group() print(system)
if system != "Windows":
owner = output_path.owner()
group = output_path.group()
print("Removing old config folder") print("Removing old config folder")
shutil.rmtree(output_path, ignore_errors=True) shutil.rmtree(output_path, ignore_errors=True)
print("Extracting zip file to config folder") print("Extracting zip file to config folder")
zip.extractall(output_path) zip.extractall(output_path)
print("Changing owner and group of config folder recursively to {}:{}".format(owner,group)) zip.close()
recursive_chown(output_path, owner, group) if system != "Windows":
print("Changing owner and group of config folder recursively to {}:{}".format(owner,group))
recursive_chown(output_path, owner, group)
print("Removing backup file") print("Removing backup file")
os.remove(backupfile) os.remove(backupfile)
else: else:

View file

@ -9,7 +9,6 @@ class ActorController(BasicController):
self.update_key = "actorupdate" self.update_key = "actorupdate"
async def on(self, id, power=None): async def on(self, id, power=None):
# logging.info("Controller_power: {}".format(power))
try: try:
item = self.find_by_id(id) item = self.find_by_id(id)
if power is None: if power is None:
@ -20,7 +19,8 @@ class ActorController(BasicController):
power = 100 power = 100
if item.instance.state is False: if item.instance.state is False:
await item.instance.on(power) await item.instance.on(power)
await self.push_udpate() #await self.push_udpate()
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict(), True) self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict(), True)
else: else:
await self.set_power(id, power) await self.set_power(id, power)
@ -33,7 +33,8 @@ class ActorController(BasicController):
item = self.find_by_id(id) item = self.find_by_id(id)
if item.instance.state is True: if item.instance.state is True:
await item.instance.off() await item.instance.off()
await self.push_udpate() #await self.push_udpate()
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict()) self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict())
except Exception as e: except Exception as e:
logging.error("Failed to switch on Actor {} {}".format(id, e), True) logging.error("Failed to switch on Actor {} {}".format(id, e), True)
@ -43,6 +44,7 @@ class ActorController(BasicController):
item = self.find_by_id(id) item = self.find_by_id(id)
instance = item.get("instance") instance = item.get("instance")
await instance.toggle() await instance.toggle()
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict()) self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict())
except Exception as e: except Exception as e:
logging.error("Failed to toggle Actor {} {}".format(id, e)) logging.error("Failed to toggle Actor {} {}".format(id, e))
@ -58,7 +60,8 @@ class ActorController(BasicController):
try: try:
item = self.find_by_id(id) item = self.find_by_id(id)
item.power = round(power) item.power = round(power)
await self.push_udpate() #await self.push_udpate()
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda item: item.to_dict(), self.data))))
self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict()) self.cbpi.push_update("cbpi/actorupdate/{}".format(id), item.to_dict())
except Exception as e: except Exception as e:
logging.error("Failed to update Actor {} {}".format(id, e)) logging.error("Failed to update Actor {} {}".format(id, e))

View file

@ -199,7 +199,8 @@ class FermentationController:
def get_state(self): def get_state(self):
if self.data == []: if self.data == []:
logging.info(self.data) #logging.info(self.data)
pass
return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types(), "steptypes":self.get_steptypes()} return {"data": list(map(lambda x: x.to_dict(), self.data)), "types":self.get_types(), "steptypes":self.get_steptypes()}

View file

@ -1,5 +1,4 @@
import asyncio import asyncio
import json import json
from re import M from re import M
@ -8,11 +7,14 @@ from contextlib import AsyncExitStack, asynccontextmanager
from cbpi import __version__ from cbpi import __version__
import logging import logging
class SatelliteController: class SatelliteController:
def __init__(self, cbpi): def __init__(self, cbpi):
self.cbpi = cbpi self.cbpi = cbpi
self.kettlecontroller = cbpi.kettle
self.fermentercontroller = cbpi.fermenter
self.sensorcontroller = cbpi.sensor
self.actorcontroller = cbpi.actor
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.host = cbpi.static_config.get("mqtt_host", "localhost") self.host = cbpi.static_config.get("mqtt_host", "localhost")
self.port = cbpi.static_config.get("mqtt_port", 1883) self.port = cbpi.static_config.get("mqtt_port", 1883)
@ -23,6 +25,11 @@ class SatelliteController:
("cbpi/actor/+/on", self._actor_on), ("cbpi/actor/+/on", self._actor_on),
("cbpi/actor/+/off", self._actor_off), ("cbpi/actor/+/off", self._actor_off),
("cbpi/actor/+/power", self._actor_power), ("cbpi/actor/+/power", self._actor_power),
("cbpi/updateactor", self._actorupdate),
("cbpi/updatekettle", self._kettleupdate),
("cbpi/updatesensor", self._sensorupdate),
("cbpi/updatefermenter", self._fermenterupdate),
] ]
self.tasks = set() self.tasks = set()
@ -63,12 +70,48 @@ class SatelliteController:
if power < 0: if power < 0:
power = 0 power = 0
await self.cbpi.actor.set_power(topic_key[2],power) await self.cbpi.actor.set_power(topic_key[2],power)
await self.cbpi.actor.actor_update(topic_key[2],power) #await self.cbpi.actor.actor_update(topic_key[2],power)
except: except:
self.logger.warning("Failed to set actor power via mqtt. No valid power in message") self.logger.warning("Failed to set actor power via mqtt. No valid power in message")
except: except:
self.logger.warning("Failed to set actor power via mqtt") self.logger.warning("Failed to set actor power via mqtt")
async def _kettleupdate(self, messages):
async for message in messages:
try:
self.kettle=self.kettlecontroller.get_state()
for item in self.kettle['data']:
self.cbpi.push_update("cbpi/{}/{}".format("kettleupdate",item['id']), item)
except Exception as e:
self.logger.warning("Failed to send kettleupdate via mqtt: {}".format(e))
async def _fermenterupdate(self, messages):
async for message in messages:
try:
self.fermenter=self.fermentercontroller.get_state()
for item in self.fermenter['data']:
self.cbpi.push_update("cbpi/{}/{}".format("fermenterupdate",item['id']), item)
except Exception as e:
self.logger.warning("Failed to send fermenterupdate via mqtt: {}".format(e))
async def _actorupdate(self, messages):
async for message in messages:
try:
self.actor=self.actorcontroller.get_state()
for item in self.actor['data']:
self.cbpi.push_update("cbpi/{}/{}".format("actorupdate",item['id']), item)
except Exception as e:
self.logger.warning("Failed to send actorupdate via mqtt: {}".format(e))
async def _sensorupdate(self, messages):
async for message in messages:
try:
self.sensor=self.sensorcontroller.get_state()
for item in self.sensor['data']:
self.cbpi.push_update("cbpi/{}/{}".format("sensorupdate",item['id']), item)
except Exception as e:
self.logger.warning("Failed to send sensorupdate via mqtt: {}".format(e))
def subcribe(self, topic, method): def subcribe(self, topic, method):
task = asyncio.create_task(self._subcribe(topic, method)) task = asyncio.create_task(self._subcribe(topic, method))
return task return task

View file

@ -977,7 +977,8 @@ class UploadController:
"Kettle": self.boilid, "Kettle": self.boilid,
"Timer": step_timer, "Timer": step_timer,
"Temp": step_temp, "Temp": step_temp,
"Sensor": cooldown_sensor "Sensor": cooldown_sensor,
"Actor": self.CoolDownActor
}, },
"status_text": "", "status_text": "",
"status": "I", "status": "I",
@ -1001,6 +1002,7 @@ class UploadController:
self.BoilTemp = self.cbpi.config.get("steps_boil_temp", 98) self.BoilTemp = self.cbpi.config.get("steps_boil_temp", 98)
#get default cooldown temp alarm setting #get default cooldown temp alarm setting
self.CoolDownTemp = self.cbpi.config.get("steps_cooldown_temp", 25) self.CoolDownTemp = self.cbpi.config.get("steps_cooldown_temp", 25)
self.CoolDownActor = self.cbpi.config.get("steps_cooldown_actor", None)
# get default Kettle from Settings # get default Kettle from Settings
self.id = self.cbpi.config.get('MASH_TUN', None) self.id = self.cbpi.config.get('MASH_TUN', None)
self.boilid = self.cbpi.config.get('BoilKettle', None) self.boilid = self.cbpi.config.get('BoilKettle', None)
@ -1030,6 +1032,7 @@ class UploadController:
"cooldown": str(self.cooldown), "cooldown": str(self.cooldown),
"boiltemp": str(self.BoilTemp), "boiltemp": str(self.BoilTemp),
"cooldowntemp": str(self.CoolDownTemp), "cooldowntemp": str(self.CoolDownTemp),
"cooldownactor": self.CoolDownActor,
"temp_unit": str(self.TEMP_UNIT), "temp_unit": str(self.TEMP_UNIT),
"AutoMode": str(self.AutoMode) "AutoMode": str(self.AutoMode)
} }

View file

@ -109,6 +109,7 @@ class CraftBeerPi:
self.log = LogController(self) self.log = LogController(self)
self.system = SystemController(self) self.system = SystemController(self)
self.kettle = KettleController(self) self.kettle = KettleController(self)
self.fermenter : FermentationController = FermentationController(self)
self.step : StepController = StepController(self) self.step : StepController = StepController(self)
self.recipe : RecipeController = RecipeController(self) self.recipe : RecipeController = RecipeController(self)
self.upload : UploadController = UploadController(self) self.upload : UploadController = UploadController(self)
@ -117,7 +118,6 @@ class CraftBeerPi:
if str(self.static_config.get("mqtt", False)).lower() == "true": if str(self.static_config.get("mqtt", False)).lower() == "true":
self.satellite: SatelliteController = SatelliteController(self) self.satellite: SatelliteController = SatelliteController(self)
self.dashboard = DashboardController(self) self.dashboard = DashboardController(self)
self.fermenter : FermentationController = FermentationController(self)
self.http_step = StepHttpEndpoints(self) self.http_step = StepHttpEndpoints(self)
self.http_recipe = RecipeHttpEndpoints(self) self.http_recipe = RecipeHttpEndpoints(self)

View file

@ -28,6 +28,7 @@ class ConfigUpdate(CBPiExtension):
default_cool_temp = 20 if TEMP_UNIT == "C" else 68 default_cool_temp = 20 if TEMP_UNIT == "C" else 68
boil_temp = self.cbpi.config.get("steps_boil_temp", None) boil_temp = self.cbpi.config.get("steps_boil_temp", None)
cooldown_sensor = self.cbpi.config.get("steps_cooldown_sensor", None) cooldown_sensor = self.cbpi.config.get("steps_cooldown_sensor", None)
cooldown_actor = self.cbpi.config.get("steps_cooldown_actor", None)
cooldown_temp = self.cbpi.config.get("steps_cooldown_temp", None) cooldown_temp = self.cbpi.config.get("steps_cooldown_temp", None)
mashin_step = self.cbpi.config.get("steps_mashin", None) mashin_step = self.cbpi.config.get("steps_mashin", None)
mash_step = self.cbpi.config.get("steps_mash", None) mash_step = self.cbpi.config.get("steps_mash", None)
@ -44,6 +45,7 @@ class ConfigUpdate(CBPiExtension):
influxdbuser = self.cbpi.config.get("INFLUXDBUSER", None) influxdbuser = self.cbpi.config.get("INFLUXDBUSER", None)
influxdbpwd = self.cbpi.config.get("INFLUXDBPWD", None) influxdbpwd = self.cbpi.config.get("INFLUXDBPWD", None)
influxdbcloud = self.cbpi.config.get("INFLUXDBCLOUD", None) influxdbcloud = self.cbpi.config.get("INFLUXDBCLOUD", None)
mqttupdate = self.cbpi.config.get("MQTTUpdate", None)
@ -61,6 +63,13 @@ class ConfigUpdate(CBPiExtension):
except: except:
logger.warning('Unable to update database') logger.warning('Unable to update database')
if cooldown_actor is None:
logger.info("INIT Cooldown Actor Setting")
try:
await self.cbpi.config.add("steps_cooldown_actor", "", ConfigType.ACTOR, "Actor to trigger cooldown water on and off (default: None)")
except:
logger.warning('Unable to update database')
if cooldown_temp is None: if cooldown_temp is None:
logger.info("INIT Cooldown Temp Setting") logger.info("INIT Cooldown Temp Setting")
try: try:
@ -255,6 +264,19 @@ class ConfigUpdate(CBPiExtension):
except: except:
logger.warning('Unable to update config') logger.warning('Unable to update config')
if mqttupdate is None:
logger.info("INIT MQTT update frequency for Kettles and Fermenters")
try:
await self.cbpi.config.add("MQTTUpdate", 0, ConfigType.SELECT, "Forced MQTT Update frequency in s for Kettle and Fermenter (no changes in payload required). Restart required after change",
[{"label": "30", "value": 30},
{"label": "60", "value": 60},
{"label": "120", "value": 120},
{"label": "300", "value": 300},
{"label": "Never", "value": 0}])
except:
logger.warning('Unable to update database')
def setup(cbpi): def setup(cbpi):
cbpi.plugin.register("ConfigUpdate", ConfigUpdate) cbpi.plugin.register("ConfigUpdate", ConfigUpdate)
pass pass

View file

@ -0,0 +1,74 @@
import logging
import asyncio
from cbpi.api import *
from cbpi.api.config import ConfigType
from cbpi.api.base import CBPiBase
from cbpi.controller.fermentation_controller import FermentationController
from cbpi.controller.kettle_controller import KettleController
logger = logging.getLogger(__name__)
class MQTTUtil(CBPiExtension):
def __init__(self,cbpi):
self.cbpi = cbpi
self.kettlecontroller = cbpi.kettle
self.fermentationcontroller = cbpi.fermenter
# sensor and actor update is done anyhow during startup
# self.sensorcontroller = cbpi.sensor
# self.actorcontroller = cbpi.actor
self.mqttupdate = int(self.cbpi.config.get("MQTTUpdate", 0))
if self.mqttupdate != 0:
self._task = asyncio.create_task(self.run())
logger.info("INIT MQTTUtil")
else:
self._task = asyncio.create_task(self.push_once())
async def push_once(self):
# wait some time to ensure that kettlecontroller is started
await asyncio.sleep(5)
self.push_update()
async def run(self):
while True:
self.push_update()
await asyncio.sleep(self.mqttupdate)
def push_update(self):
# try:
# self.actor=self.actorcontroller.get_state()
# for item in self.actor['data']:
# self.cbpi.push_update("cbpi/{}/{}".format("actorupdate",item['id']), item)
# except Exception as e:
# logging.error(e)
# pass
# try:
# self.sensor=self.sensorcontroller.get_state()
# for item in self.sensor['data']:
# self.cbpi.push_update("cbpi/{}/{}".format("sensorupdate",item['id']), item)
# except Exception as e:
# logging.error(e)
# pass
try:
self.kettle=self.kettlecontroller.get_state()
for item in self.kettle['data']:
self.cbpi.push_update("cbpi/{}/{}".format("kettleupdate",item['id']), item)
except Exception as e:
logging.error(e)
pass
try:
self.fermenter=self.fermentationcontroller.get_state()
for item in self.fermenter['data']:
self.cbpi.push_update("cbpi/{}/{}".format("fermenterupdate",item['id']), item)
except Exception as e:
logging.error(e)
pass
def setup(cbpi):
if str(cbpi.static_config.get("mqtt", False)).lower() == "true":
cbpi.plugin.register("MQTTUtil", MQTTUtil)
pass

View file

@ -0,0 +1,3 @@
name: MQTTUtil
version: 4
active: true

View file

@ -41,7 +41,7 @@ class ReadThread (threading.Thread):
try: try:
if self.sensor_name is None: if self.sensor_name is None:
return return
with open('/sys/bus/w1/devices/w1_bus_master1/%s/w1_slave' % self.sensor_name, 'r') as content_file: with open('/sys/bus/w1/devices/%s/w1_slave' % self.sensor_name, 'r') as content_file:
content = content_file.read() content = content_file.read()
if (content.split('\n')[0].split(' ')[11] == "YES"): if (content.split('\n')[0].split(' ')[11] == "YES"):
temp = float(content.split("=")[-1]) / 1000 # temp in Celcius temp = float(content.split("=")[-1]) / 1000 # temp in Celcius

View file

@ -32,7 +32,11 @@ class CBPiWebSocket:
self.logger.debug("broadcast to ws clients. Data: %s" % data) self.logger.debug("broadcast to ws clients. Data: %s" % data)
for ws in self._clients: for ws in self._clients:
async def send_data(ws, data): async def send_data(ws, data):
await ws.send_json(data=data, dumps=json_dumps) try:
await ws.send_json(data=data, dumps=json_dumps)
except Exception as e:
self.logger.error("Error with client %s: %s" % (ws, str(e)))
self.cbpi.app.loop.create_task(send_data(ws, data)) self.cbpi.app.loop.create_task(send_data(ws, data))
async def websocket_handler(self, request): async def websocket_handler(self, request):
@ -85,4 +89,4 @@ class CBPiWebSocket:
self.logger.info("Web Socket Close") self.logger.info("Web Socket Close")
return ws return ws