mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-09-08 01:43:41 +02:00
commit
8b42600781
11 changed files with 296 additions and 50 deletions
|
@ -1,3 +1,3 @@
|
|||
__version__ = "4.4.1.rc1"
|
||||
__version__ = "4.4.3"
|
||||
__codename__ = "Yeast Starter"
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@ from cbpi.utils.utils import load_config
|
|||
from zipfile import ZipFile
|
||||
from cbpi.craftbeerpi import CraftBeerPi
|
||||
import os
|
||||
try:
|
||||
import pwd
|
||||
module_pwd=True
|
||||
except:
|
||||
module_pwd=False
|
||||
import pkgutil
|
||||
import shutil
|
||||
import click
|
||||
|
@ -165,7 +170,8 @@ class CraftBeerPiCli():
|
|||
else:
|
||||
print("CraftBeerPi Autostart is {}OFF{}".format(Fore.RED,Style.RESET_ALL))
|
||||
elif(name == "on"):
|
||||
user=os.getlogin()
|
||||
#user=os.getlogin()
|
||||
user=pwd.getpwuid(os.getuid()).pw_name
|
||||
path="/usr/local/bin/cbpi"
|
||||
if os.path.exists("/home/"+user+"/.local/bin/cbpi") is True:
|
||||
path="/home/"+user+"/.local/bin/cbpi"
|
||||
|
|
|
@ -11,6 +11,7 @@ mqtt_host: localhost
|
|||
mqtt_port: 1883
|
||||
mqtt_username: ""
|
||||
mqtt_password: ""
|
||||
mqtt_offset: false
|
||||
|
||||
username: cbpi
|
||||
password: 123
|
||||
|
|
|
@ -17,13 +17,12 @@ import os.path
|
|||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
import json
|
||||
import shortuuid
|
||||
import math
|
||||
import yaml
|
||||
from ..api.step import StepMove, StepResult, StepState
|
||||
import re
|
||||
import base64
|
||||
|
||||
|
||||
class UploadController:
|
||||
|
||||
def __init__(self, cbpi):
|
||||
|
@ -70,9 +69,12 @@ class UploadController:
|
|||
return []
|
||||
|
||||
async def get_brewfather_recipes(self,offset=0):
|
||||
limit = 50
|
||||
length = self.cbpi.config.get('brewfather_list_length',50)
|
||||
repeat = True
|
||||
brewfather = True
|
||||
result=[]
|
||||
self.url="https://api.brewfather.app/v1/recipes"
|
||||
self.url="https://api.brewfather.app/v2/recipes"
|
||||
brewfather_user_id = self.cbpi.config.get("brewfather_user_id", None)
|
||||
if brewfather_user_id == "" or brewfather_user_id is None:
|
||||
brewfather = False
|
||||
|
@ -84,25 +86,63 @@ class UploadController:
|
|||
if brewfather == True:
|
||||
encodedData = base64.b64encode(bytes(f"{brewfather_user_id}:{brewfather_api_key}", "ISO-8859-1")).decode("ascii")
|
||||
headers={"Authorization": "Basic %s" % encodedData}
|
||||
parameters={"limit": 50, 'offset': offset}
|
||||
async with aiohttp.ClientSession(headers=headers) as bf_session:
|
||||
async with bf_session.get(self.url, params=parameters) as r:
|
||||
bf_recipe_list = await r.json()
|
||||
await bf_session.close()
|
||||
|
||||
if bf_recipe_list:
|
||||
for row in bf_recipe_list:
|
||||
recipe_id = row['_id']
|
||||
name = row['name']
|
||||
element = {'value': recipe_id, 'label': name}
|
||||
result.append(element)
|
||||
return result
|
||||
else:
|
||||
return []
|
||||
|
||||
else:
|
||||
return []
|
||||
|
||||
parameters={"limit": limit}
|
||||
while repeat == True:
|
||||
try:
|
||||
async with aiohttp.ClientSession(headers=headers) as bf_session:
|
||||
async with bf_session.get(self.url, params=parameters) as r:
|
||||
if r.status == 429:
|
||||
try:
|
||||
seconds=int(r.headers['Retry-After'])
|
||||
minutes=round(seconds/60)
|
||||
except:
|
||||
seconds=None
|
||||
if not seconds:
|
||||
logging.error("Too many requests to BF api. Try again later")
|
||||
self.cbpi.notify("Error", "Too many requests to BF api. Try again later", NotificationType.ERROR)
|
||||
else:
|
||||
logging.error(f"Too many requests to BF api. Try in {minutes} minutes again.")
|
||||
self.cbpi.notify("Error", f"Too many requests to BF api. Try in {minutes} minutes again.", NotificationType.ERROR)
|
||||
repeat = False
|
||||
logging.error(r.headers['Retry-After'])
|
||||
else:
|
||||
bf_recipe_list = await r.json()
|
||||
await bf_session.close()
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
repeat = False
|
||||
try:
|
||||
if bf_recipe_list:
|
||||
for row in bf_recipe_list:
|
||||
recipe_id = row['_id']
|
||||
name = row['name']
|
||||
element = {'value': recipe_id, 'label': name}
|
||||
result.append(element)
|
||||
else:
|
||||
repeat = False
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
try:
|
||||
if len(bf_recipe_list) != limit:
|
||||
repeat = False
|
||||
else:
|
||||
parameters={"limit": limit, 'start_after': recipe_id}
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
try:
|
||||
newlist = sorted(result, key=lambda d: d['label'])
|
||||
listlength=len(newlist)
|
||||
max=math.floor(listlength/length)
|
||||
sortlist=[]
|
||||
for i in range(0 , max+1):
|
||||
sortlist.append({ 'value': i*length, 'label': i*length })
|
||||
return newlist, sortlist, length
|
||||
except:
|
||||
logging.error("Return empty BF recipe list")
|
||||
sortlist=[{ 'value': 0, 'label': '0' }]
|
||||
return result, sortlist, length
|
||||
|
||||
|
||||
def get_creation_path(self):
|
||||
creation_path = self.cbpi.config.get("RECIPE_CREATION_PATH", "upload")
|
||||
|
@ -738,7 +778,7 @@ class UploadController:
|
|||
|
||||
brewfather = True
|
||||
result=[]
|
||||
self.bf_url="https://api.brewfather.app/v1/recipes/" + Recipe_ID
|
||||
self.bf_url="https://api.brewfather.app/v2/recipes/" + Recipe_ID
|
||||
brewfather_user_id = self.cbpi.config.get("brewfather_user_id", None)
|
||||
if brewfather_user_id == "" or brewfather_user_id is None:
|
||||
brewfather = False
|
||||
|
@ -775,6 +815,21 @@ class UploadController:
|
|||
except:
|
||||
miscs = None
|
||||
|
||||
try:
|
||||
fermentation_steps=bf_recipe['fermentation']['steps']
|
||||
except:
|
||||
fermentation_steps=None
|
||||
|
||||
if fermentation_steps is not None:
|
||||
try:
|
||||
step=fermentation_steps[0]
|
||||
self.fermentation_step_temp=int(step['stepTemp'])
|
||||
except:
|
||||
self.fermentation_step_temp=None
|
||||
|
||||
if self.fermentation_step_temp is not None and self.TEMP_UNIT != "C":
|
||||
self.fermentation_step_temp = round((9.0 / 5.0 * float(self.fermentation_step_temp)+ 32))
|
||||
|
||||
FirstWort = self.getFirstWort(hops, "bf")
|
||||
|
||||
await self.create_recipe(RecipeName)
|
||||
|
@ -1012,8 +1067,9 @@ class UploadController:
|
|||
cooldown_sensor = self.cbpi.config.get("steps_cooldown_sensor", None)
|
||||
if cooldown_sensor is None or cooldown_sensor == '':
|
||||
cooldown_sensor = self.boilkettle.sensor # fall back to boilkettle sensor if no other sensor is specified
|
||||
step_timer = ""
|
||||
step_temp = int(self.CoolDownTemp)
|
||||
step_timer = ""
|
||||
|
||||
step_temp = int(self.CoolDownTemp) if (self.fermentation_step_temp is None or self.fermentation_step_temp <= int(self.CoolDownTemp)) else self.fermentation_step_temp
|
||||
step_string = { "name": "Cooldown",
|
||||
"props": {
|
||||
"Kettle": self.boilid,
|
||||
|
|
|
@ -8,7 +8,7 @@ import json
|
|||
from cbpi.api import *
|
||||
from cbpi.api.config import ConfigType
|
||||
from cbpi.api.base import CBPiBase
|
||||
import glob
|
||||
import glob, yaml
|
||||
from cbpi import __version__
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -19,6 +19,12 @@ class ConfigUpdate(CBPiExtension):
|
|||
self.cbpi = cbpi
|
||||
self._task = asyncio.create_task(self.run())
|
||||
|
||||
def append_to_yaml(self, file_path, data_to_append):
|
||||
|
||||
with open(file_path[0], 'a+') as file:
|
||||
file.seek(0)
|
||||
yaml.dump(data_to_append, file, default_flow_style=False)
|
||||
|
||||
|
||||
async def run(self):
|
||||
logging.info("Check Config for required changes")
|
||||
|
@ -61,12 +67,13 @@ class ConfigUpdate(CBPiExtension):
|
|||
AddMashIn = self.cbpi.config.get("AddMashInStep", None)
|
||||
bfuserid = self.cbpi.config.get("brewfather_user_id", None)
|
||||
bfapikey = self.cbpi.config.get("brewfather_api_key", None)
|
||||
bflistlength = self.cbpi.config.get("brewfather_list_length", None)
|
||||
RecipeCreationPath = self.cbpi.config.get("RECIPE_CREATION_PATH", None)
|
||||
BoilKettle = self.cbpi.config.get("BoilKettle", None)
|
||||
CONFIG_STATUS = self.cbpi.config.get("CONFIG_STATUS", None)
|
||||
self.version=__version__
|
||||
current_grid = self.cbpi.config.get("current_grid", None)
|
||||
|
||||
mqtt_offset=self.cbpi.static_config.get("mqtt_offset", None)
|
||||
|
||||
if boil_temp is None:
|
||||
logger.info("INIT Boil Temp Setting")
|
||||
|
@ -244,6 +251,21 @@ class ConfigUpdate(CBPiExtension):
|
|||
await self.cbpi.config.add("brewfather_api_key", "", type=ConfigType.STRING, description="Brewfather API Key", source="craftbeerpi")
|
||||
except:
|
||||
logger.warning('Unable to update config')
|
||||
|
||||
## Check if Brewfather API Key is in config
|
||||
|
||||
if bflistlength is None:
|
||||
logger.info("INIT Brewfather Recipe List Length")
|
||||
try:
|
||||
await self.cbpi.config.add("brewfather_list_length", 50, type=ConfigType.SELECT, description="Brewfather Recipe List length",
|
||||
source="craftbeerpi",
|
||||
options= [{"label": "5", "value": 5},
|
||||
{"label": "10", "value": 10},
|
||||
{"label": "25", "value": 25},
|
||||
{"label": "50", "value": 50},
|
||||
{"label": "100", "value": 100}])
|
||||
except:
|
||||
logger.warning('Unable to update config')
|
||||
|
||||
## Check if Brewfather API Key is in config
|
||||
|
||||
|
@ -542,6 +564,16 @@ class ConfigUpdate(CBPiExtension):
|
|||
except Exception as e:
|
||||
logging.error(e)
|
||||
|
||||
if mqtt_offset is None:
|
||||
logging.info("INIT MQTT Offset in static config")
|
||||
try:
|
||||
static_config_file=glob.glob(self.cbpi.config_folder.get_file_path('config.yaml'))
|
||||
data_to_append = {'mqtt_offset': False}
|
||||
self.append_to_yaml(static_config_file, data_to_append)
|
||||
pass
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
logging.warning('Unable to update database')
|
||||
|
||||
## Check if influxdbname is in config
|
||||
if CONFIG_STATUS is None or CONFIG_STATUS != self.version:
|
||||
|
|
|
@ -536,7 +536,7 @@ class CooldownStep(CBPiStep):
|
|||
if time.time() >= self.next_check:
|
||||
self.next_check = time.time() + (self.Interval * 60)
|
||||
|
||||
cooldown_model = np.poly1d(np.polyfit(self.temp_array, self.time_array, 2))
|
||||
cooldown_model = np.polynomial.polynomial.Polynomial.fit(self.temp_array, self.time_array, 2)
|
||||
target_time=cooldown_model(self.target_temp)
|
||||
target_timestring= datetime.fromtimestamp(target_time)
|
||||
self.summary="ECT: {}".format(target_timestring.strftime("%H:%M"))
|
||||
|
|
|
@ -8,16 +8,17 @@ import json
|
|||
import time
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@parameters([Property.Text(label="Topic", configurable=True, description="MQTT Topic"),
|
||||
Property.Text(label="PayloadDictionary", configurable=True, default_value="",
|
||||
description="Where to find msg in payload, leave blank for raw payload"),
|
||||
Property.Kettle(label="Kettle", description="Reduced logging if Kettle is inactive / range warning in dashboard (only Kettle or Fermenter to be selected)"),
|
||||
Property.Fermenter(label="Fermenter", description="Reduced logging if Fermenter is inactive / range warning in dashboard (only Kettle or Fermenter to be selected)"),
|
||||
Property.Number(label="ReducedLogging", configurable=True, description="Reduced logging frequency in seconds if selected Kettle or Fermenter is inactive (default:60 sec | 0 disabled)"),
|
||||
Property.Number(label="Timeout", configurable=True, unit="sec",
|
||||
description="Timeout in seconds to send notification (default:60 | deactivated: 0)"),
|
||||
Property.Number(label="TempRange", configurable=True, unit="degree",
|
||||
description="Temp range in degree between reading and target temp of fermenter/kettle. Larger difference shows different color in dashboard (default:0 | deactivated: 0)")])
|
||||
Property.Text(label="PayloadDictionary", configurable=True, default_value="",
|
||||
description="Where to find msg in payload, leave blank for raw payload"),
|
||||
Property.Kettle(label="Kettle", description="Reduced logging if Kettle is inactive / range warning in dashboard (only Kettle or Fermenter to be selected)"),
|
||||
Property.Fermenter(label="Fermenter", description="Reduced logging if Fermenter is inactive / range warning in dashboard (only Kettle or Fermenter to be selected)"),
|
||||
Property.Number(label="ReducedLogging", configurable=True, description="Reduced logging frequency in seconds if selected Kettle or Fermenter is inactive (default:60 sec | 0 disabled)"),
|
||||
Property.Number(label="Timeout", configurable=True, unit="sec",
|
||||
description="Timeout in seconds to send notification (default:60 | deactivated: 0)"),
|
||||
Property.Number(label="TempRange", configurable=True, unit="degree",
|
||||
description="Temp range in degree between reading and target temp of fermenter/kettle. Larger difference shows different color in dashboard (default:0 | deactivated: 0)")])
|
||||
class MQTTSensor(CBPiSensor):
|
||||
|
||||
def __init__(self, cbpi, id, props):
|
||||
|
@ -135,6 +136,135 @@ class MQTTSensor(CBPiSensor):
|
|||
async def on_stop(self):
|
||||
self.subscribed = self.cbpi.satellite.unsubscribe(self.Topic, self.on_message)
|
||||
|
||||
@parameters([Property.Text(label="Topic", configurable=True, description="MQTT Topic"),
|
||||
Property.Text(label="PayloadDictionary", configurable=True, default_value="",
|
||||
description="Where to find msg in payload, leave blank for raw payload"),
|
||||
Property.Kettle(label="Kettle", description="Reduced logging if Kettle is inactive / range warning in dashboard (only Kettle or Fermenter to be selected)"),
|
||||
Property.Fermenter(label="Fermenter", description="Reduced logging if Fermenter is inactive / range warning in dashboard (only Kettle or Fermenter to be selected)"),
|
||||
Property.Number(label="Offset", configurable=True, description="Offset for MQTT Sensor (default is 0). !!! Use this only with caution as offset for MQTT sensor should be defined on Sensor side !!!"),
|
||||
Property.Number(label="ReducedLogging", configurable=True, description="Reduced logging frequency in seconds if selected Kettle or Fermenter is inactive (default:60 sec | 0 disabled)"),
|
||||
Property.Number(label="Timeout", configurable=True, unit="sec",
|
||||
description="Timeout in seconds to send notification (default:60 | deactivated: 0)"),
|
||||
Property.Number(label="TempRange", configurable=True, unit="degree",
|
||||
description="Temp range in degree between reading and target temp of fermenter/kettle. Larger difference shows different color in dashboard (default:0 | deactivated: 0)")])
|
||||
class MQTTSensorOffset(CBPiSensor):
|
||||
|
||||
def __init__(self, cbpi, id, props):
|
||||
super(MQTTSensorOffset, self).__init__(cbpi, id, props)
|
||||
self.Topic = self.props.get("Topic", None)
|
||||
self.offset = float(self.props.get("Offset", 0))
|
||||
self.payload_text = self.props.get("PayloadDictionary", None)
|
||||
if self.payload_text != None:
|
||||
self.payload_text = self.payload_text.split('.')
|
||||
self.subscribed = self.cbpi.satellite.subscribe(self.Topic, self.on_message)
|
||||
self.value: float = 999
|
||||
self.timeout=int(self.props.get("Timeout", 60))
|
||||
self.temprange=float(self.props.get("TempRange", 0))
|
||||
self.starttime = time.time()
|
||||
self.notificationsend = False
|
||||
self.nextchecktime=self.starttime+self.timeout
|
||||
self.lastdata=time.time()
|
||||
self.lastlog=0
|
||||
self.sensor=self.get_sensor(self.id)
|
||||
self.reducedfrequency=int(self.props.get("ReducedLogging", 60))
|
||||
if self.reducedfrequency < 0:
|
||||
self.reducedfrequency = 0
|
||||
self.kettleid=self.props.get("Kettle", None)
|
||||
self.fermenterid=self.props.get("Fermenter", None)
|
||||
self.reducedlogging = True if self.kettleid or self.fermenterid else False
|
||||
|
||||
if self.kettleid is not None and self.fermenterid is not None:
|
||||
self.reducedlogging=False
|
||||
self.cbpi.notify("MQTTSensor", "Sensor '" + str(self.sensor.name) + "' cant't have Fermenter and Kettle defined for reduced logging / range warning.", NotificationType.WARNING, action=[NotificationAction("OK", self.Confirm)])
|
||||
|
||||
async def Confirm(self, **kwargs):
|
||||
self.nextchecktime = time.time() + self.timeout
|
||||
self.notificationsend = False
|
||||
pass
|
||||
|
||||
async def message(self):
|
||||
target_timestring= datetime.fromtimestamp(self.lastdata)
|
||||
self.cbpi.notify("MQTTSensor Timeout", "Sensor '" + str(self.sensor.name) + "' did not respond. Last data received: "+target_timestring.strftime("%D %H:%M"), NotificationType.WARNING, action=[NotificationAction("OK", self.Confirm)])
|
||||
pass
|
||||
|
||||
async def on_message(self, message):
|
||||
val = json.loads(message.payload.decode())
|
||||
try:
|
||||
if self.payload_text is not None:
|
||||
for key in self.payload_text:
|
||||
val = val.get(key, None)
|
||||
|
||||
if isinstance(val, (int, float, str)):
|
||||
self.value = float(val)+self.offset
|
||||
self.push_update(self.value)
|
||||
if self.reducedlogging == True:
|
||||
await self.logvalue()
|
||||
else:
|
||||
logging.info("MQTTSensor {} regular logging".format(self.sensor.name))
|
||||
self.log_data(self.value)
|
||||
self.lastlog = time.time()
|
||||
|
||||
if self.timeout !=0:
|
||||
self.nextchecktime = time.time() + self.timeout
|
||||
self.notificationsend = False
|
||||
self.lastdata=time.time()
|
||||
except Exception as e:
|
||||
logging.error("MQTT Sensor Error {}".format(e))
|
||||
|
||||
async def logvalue(self):
|
||||
self.kettle = self.get_kettle(self.kettleid) if self.kettleid is not None else None
|
||||
self.fermenter = self.get_fermenter(self.fermenterid) if self.fermenterid is not None else None
|
||||
now=time.time()
|
||||
if self.kettle is not None:
|
||||
try:
|
||||
kettlestatus=self.kettle.instance.state
|
||||
except:
|
||||
kettlestatus=False
|
||||
if kettlestatus:
|
||||
self.log_data(self.value)
|
||||
logging.info("MQTTSensor {} Kettle Active".format(self.sensor.name))
|
||||
self.lastlog = time.time()
|
||||
else:
|
||||
logging.info("MQTTSensor {} Kettle Inactive".format(self.sensor.name))
|
||||
if self.reducedfrequency != 0:
|
||||
if now >= self.lastlog + self.reducedfrequency:
|
||||
self.log_data(self.value)
|
||||
self.lastlog = time.time()
|
||||
logging.info("Logged with reduced freqency")
|
||||
pass
|
||||
|
||||
if self.fermenter is not None:
|
||||
try:
|
||||
fermenterstatus=self.fermenter.instance.state
|
||||
except:
|
||||
fermenterstatus=False
|
||||
if fermenterstatus:
|
||||
self.log_data(self.value)
|
||||
logging.info("MQTTSensor {} Fermenter Active".format(self.sensor.name))
|
||||
self.lastlog = time.time()
|
||||
else:
|
||||
logging.info("MQTTSensor {} Fermenter Inactive".format(self.sensor.name))
|
||||
if self.reducedfrequency != 0:
|
||||
if now >= self.lastlog + self.reducedfrequency:
|
||||
self.log_data(self.value)
|
||||
self.lastlog = time.time()
|
||||
logging.info("Logged with reduced freqency")
|
||||
pass
|
||||
|
||||
async def run(self):
|
||||
while self.running:
|
||||
if self.timeout !=0:
|
||||
if time.time() > self.nextchecktime and self.notificationsend == False:
|
||||
await self.message()
|
||||
self.notificationsend=True
|
||||
await asyncio.sleep(1)
|
||||
|
||||
def get_state(self):
|
||||
return dict(value=self.value)
|
||||
|
||||
async def on_stop(self):
|
||||
self.subscribed = self.cbpi.satellite.unsubscribe(self.Topic, self.on_message)
|
||||
|
||||
|
||||
def setup(cbpi):
|
||||
'''
|
||||
|
@ -145,4 +275,7 @@ def setup(cbpi):
|
|||
:return:
|
||||
'''
|
||||
if str(cbpi.static_config.get("mqtt", False)).lower() == "true":
|
||||
cbpi.plugin.register("MQTTSensor", MQTTSensor)
|
||||
if str(cbpi.static_config.get("mqtt_offset", False)).lower() == "false":
|
||||
cbpi.plugin.register("MQTTSensor", MQTTSensor)
|
||||
else:
|
||||
cbpi.plugin.register("MQTTSensor", MQTTSensorOffset)
|
||||
|
|
|
@ -43,6 +43,7 @@ class SystemHttpEndpoints:
|
|||
fermentersteps=self.cbpi.fermenter.get_fermenter_steps(),
|
||||
config=self.cbpi.config.get_state(),
|
||||
notifications=self.cbpi.notification.get_state(),
|
||||
bf_recipes=await self.cbpi.upload.get_brewfather_recipes(0),
|
||||
version=__version__,
|
||||
guiversion=version,
|
||||
codename=__codename__)
|
||||
|
|
|
@ -159,6 +159,23 @@ class UploadHttpEndpoints():
|
|||
|
||||
return web.json_response(bf_list)
|
||||
|
||||
@request_mapping(path='/bfupdate/', method="GET", auth_required=False)
|
||||
async def get_bf_update(self, request):
|
||||
"""
|
||||
|
||||
---
|
||||
description: Get recipe list update from Brewfather App
|
||||
tags:
|
||||
- Upload
|
||||
responses:
|
||||
"200":
|
||||
description: successful operation
|
||||
"""
|
||||
#offset = request.match_info['offset']
|
||||
bf_list = await self.controller.get_brewfather_recipes()
|
||||
self.cbpi.ws.send(dict(topic="bfupdate", data=bf_list))
|
||||
return web.Response(status=200)
|
||||
|
||||
@request_mapping(path='/bf', method="POST", auth_required=False)
|
||||
async def create_bf_recipe(self, request):
|
||||
"""
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
typing-extensions>=4
|
||||
aiohttp==3.9.4
|
||||
aiohttp==3.9.5
|
||||
aiohttp-auth==0.1.1
|
||||
aiohttp-route-decorator==0.1.4
|
||||
aiohttp-security==0.5.0
|
||||
|
@ -8,7 +8,7 @@ aiohttp-swagger==1.0.16
|
|||
async-timeout==4.0.3
|
||||
aiojobs==1.2.1
|
||||
aiosqlite==0.17.0
|
||||
cryptography==42.0.5
|
||||
cryptography==42.0.8
|
||||
pyopenssl==24.1.0
|
||||
requests==2.32.2
|
||||
voluptuous==0.14.2
|
||||
|
@ -16,12 +16,12 @@ pyfiglet==1.0.2
|
|||
pandas==2.2.2
|
||||
shortuuid==1.0.13
|
||||
tabulate==0.9.0
|
||||
numpy==1.26.4
|
||||
numpy==2.0.0
|
||||
cbpi4gui
|
||||
click==8.1.7
|
||||
importlib_metadata==4.11.1
|
||||
aiomqtt==2.1.0
|
||||
psutil==5.9.8
|
||||
aiomqtt==2.2.0
|
||||
psutil==6.0.0
|
||||
zipp>=0.5
|
||||
colorama==0.4.6
|
||||
pytest-aiohttp
|
||||
|
|
10
setup.py
10
setup.py
|
@ -39,7 +39,7 @@ setup(name='cbpi4',
|
|||
long_description_content_type='text/markdown',
|
||||
install_requires=[
|
||||
"typing-extensions>=4",
|
||||
"aiohttp==3.9.4",
|
||||
"aiohttp==3.9.5",
|
||||
"aiohttp-auth==0.1.1",
|
||||
"aiohttp-route-decorator==0.1.4",
|
||||
"aiohttp-security==0.5.0",
|
||||
|
@ -48,7 +48,7 @@ setup(name='cbpi4',
|
|||
"async-timeout==4.0.3",
|
||||
"aiojobs==1.2.1 ",
|
||||
"aiosqlite==0.17.0",
|
||||
"cryptography==42.0.5",
|
||||
"cryptography==42.0.8",
|
||||
"pyopenssl==24.1.0",
|
||||
"requests==2.32.2",
|
||||
"voluptuous==0.14.2",
|
||||
|
@ -56,13 +56,13 @@ setup(name='cbpi4',
|
|||
'click==8.1.7',
|
||||
'shortuuid==1.0.13',
|
||||
'tabulate==0.9.0',
|
||||
'aiomqtt==2.1.0',
|
||||
'aiomqtt==2.2.0',
|
||||
'inquirer==3.2.4',
|
||||
'colorama==0.4.6',
|
||||
'psutil==5.9.8',
|
||||
'psutil==6.0.0',
|
||||
'cbpi4gui',
|
||||
'importlib_metadata',
|
||||
'numpy==1.26.4',
|
||||
'numpy==2.0.0',
|
||||
'pandas==2.2.2'] + (
|
||||
['rpi-lgpio'] if raspberrypi else [] ) + (
|
||||
['systemd-python'] if localsystem == "Linux" else [] ),
|
||||
|
|
Loading…
Reference in a new issue