Skip to content

Commit

Permalink
Merge pull request #120 from PiBrewing/development
Browse files Browse the repository at this point in the history
merge from Development to allow for installation with pipx under bookworm
  • Loading branch information
avollkopf authored Nov 19, 2023
2 parents 47be753 + a934de1 commit 42d8a6c
Show file tree
Hide file tree
Showing 18 changed files with 190 additions and 84 deletions.
4 changes: 2 additions & 2 deletions cbpi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__version__ = "4.1.11"
__codename__ = "Groundhog Day"
__version__ = "4.2.0"
__codename__ = "Indian Summer"

108 changes: 81 additions & 27 deletions cbpi/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging
import sys
from pathlib import Path
import requests
from cbpi import __version__, __codename__
from cbpi.configFolder import ConfigFolder
from cbpi.utils.utils import load_config
from zipfile import ZipFile
Expand Down Expand Up @@ -38,14 +40,27 @@ def start(self):

def setup_one_wire(self):
print("Setting up 1Wire")
with open('/boot/config.txt', 'w') as f:
f.write("dtoverlay=w1-gpio,gpiopin=4,pullup=on")
with open('/boot/config.txt', 'r') as f:
lines=f.readlines()
lines.append("dtoverlay=w1-gpio,gpiopin=4,pullup=on")

configtempfile=os.path.join(self.config.get_file_path(""),"config.txt")

with open(configtempfile, 'w') as f:
for line in lines:
f.write(line)
destfile="/boot/config.txt"

#copy and remove afterwards as mv will work, but raise an error message due to different file owners
shutil.os.system('sudo cp "{}" "{}"'.format(configtempfile,destfile))
shutil.os.system('rm -rf "{}"'.format(configtempfile))

print("/boot/config.txt created")

def list_one_wire(self):
print("List 1Wire")
call(["modprobe", "w1-gpio"])
call(["modprobe", "w1-therm"])
call(["sudo","modprobe", "w1-gpio"])
call(["sudo","modprobe", "w1-therm"])
try:
for dirname in os.listdir('/sys/bus/w1/devices'):
if (dirname.startswith("28") or dirname.startswith("10")):
Expand Down Expand Up @@ -150,46 +165,62 @@ def autostart(self, name):
else:
print("CraftBeerPi Autostart is {}OFF{}".format(Fore.RED,Style.RESET_ALL))
elif(name == "on"):
user=os.getlogin()
path="/usr/local/bin/cbpi"
if os.path.exists("/home/"+user+"/.local/bin/cbpi") is True:
path="/home/"+user+"/.local/bin/cbpi"
print("Add craftbeerpi.service to systemd")
try:
if os.path.exists(os.path.join("/etc/systemd/system","craftbeerpi.service")) is False:
templatefile=self.config.get_file_path("craftbeerpi.template")
shutil.os.system('cp "{}" "{}"'.format(templatefile,self.config.get_file_path("craftbeerpi.service")))
srcfile = self.config.get_file_path("craftbeerpi.service")
import jinja2

templateLoader = jinja2.FileSystemLoader(searchpath=os.path.join(self.config.get_file_path("")))
templateEnv = jinja2.Environment(loader=templateLoader)
operatingsystem = str(platform.system()).lower()
if operatingsystem.startswith("win"):
srcfile=str(srcfile).replace('\\','/')

template = templateEnv.get_template("craftbeerpi.service")
outputText = template.render(user=user, path=path)
with open(srcfile, "w") as fh:
fh.write(outputText)
destfile = os.path.join("/etc/systemd/system")
shutil.copy(srcfile, destfile)
shutil.os.system('sudo mv "{}" "{}"'.format(srcfile,destfile))
print("Copied craftbeerpi.service to /etc/systemd/system")
os.system('systemctl enable craftbeerpi.service')
shutil.os.system('sudo systemctl enable craftbeerpi.service')
print('Enabled craftbeerpi service')
os.system('systemctl start craftbeerpi.service')
shutil.os.system('sudo systemctl start craftbeerpi.service')
print('Started craftbeerpi.service')
else:
print("craftbeerpi.service is already located in /etc/systemd/system")
except Exception as e:
print(e)
return
return
elif(name == "off"):
elif(name == "off"):
print("Remove craftbeerpi.service from systemd")
try:
status = os.popen('systemctl list-units --type=service --state=running | grep craftbeerpi.service').read()
if status.find("craftbeerpi.service") != -1:
os.system('systemctl stop craftbeerpi.service')
shutil.os.system('sudo systemctl stop craftbeerpi.service')
print('Stopped craftbeerpi service')
os.system('systemctl disable craftbeerpi.service')
shutil.os.system('sudo systemctl disable craftbeerpi.service')
print('Removed craftbeerpi.service as service')
else:
print('craftbeerpi.service service is not running')

if os.path.exists(os.path.join("/etc/systemd/system","craftbeerpi.service")) is True:
os.remove(os.path.join("/etc/systemd/system","craftbeerpi.service"))
shutil.os.system('sudo rm -rf "{}"'.format(os.path.join("/etc/systemd/system","craftbeerpi.service")))
print("Deleted craftbeerpi.service from /etc/systemd/system")
else:
print("craftbeerpi.service is not located in /etc/systemd/system")
except Exception as e:
print(e)
return
return


def chromium(self, name):
'''Enable or disable autostart'''
if(name == "status"):
Expand All @@ -203,7 +234,7 @@ def chromium(self, name):
if os.path.exists(os.path.join("/etc/xdg/autostart/","chromium.desktop")) is False:
srcfile = self.config.get_file_path("chromium.desktop")
destfile = os.path.join("/etc/xdg/autostart/")
shutil.copy(srcfile, destfile)
shutil.os.system('sudo cp "{}" "{}"'.format(srcfile,destfile))
print("Copied chromium.desktop to /etc/xdg/autostart/")
else:
print("chromium.desktop is already located in /etc/xdg/autostart/")
Expand All @@ -215,7 +246,7 @@ def chromium(self, name):
print("Remove chromium.desktop from /etc/xdg/autostart/")
try:
if os.path.exists(os.path.join("/etc/xdg/autostart/","chromium.desktop")) is True:
os.remove(os.path.join("/etc/xdg/autostart/","chromium.desktop"))
shutil.os.system('sudo rm -rf "{}"'.format(os.path.join("/etc/xdg/autostart/","chromium.desktop")))
print("Deleted chromium.desktop from /etc/xdg/autostart/")
else:
print("chromium.desktop is not located in /etc/xdg/autostart/")
Expand All @@ -229,16 +260,27 @@ def chromium(self, name):
@click.pass_context
@click.option('--config-folder-path', '-c', default="./config", type=click.Path(), help="Specify where the config folder is located. Defaults to './config'.")
@click.option('--logs-folder-path', '-l', default="", type=click.Path(), help="Specify where the log folder is located. Defaults to '../logs' relative from the config folder.")
@click.option('--debug-log-level', '-d', default="30", type=int, help="Specify the log level you want to write to all logs. 0=ALL, 10=DEBUG, 20=INFO 30(default)=WARNING, 40=ERROR, 50=CRITICAL")
@click.option('--debug-log-level', '-d', default="99", type=int, help="Specify the log level you want to write to all logs. 0=ALL, 10=DEBUG, 20=INFO 30(default)=WARNING, 40=ERROR, 50=CRITICAL. Can be also set in config.yaml (debug-log-level: INT)")
def main(context, config_folder_path, logs_folder_path, debug_log_level):
print("---------------------")
print("Welcome to CBPi")
print("---------------------")
print("--------------------------")
print("Welcome to CBPi "+__version__)
print("--------------------------")
if logs_folder_path == "":
logs_folder_path = os.path.join(Path(config_folder_path).absolute().parent, 'logs')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
config=ConfigFolder(config_folder_path, logs_folder_path)
static_config = load_config(config.get_file_path("config.yaml"))
try:
if debug_log_level == 99:
debug_log_level=static_config['debug-log-level']
except:
debug_log_level=30

logging.basicConfig(format=formatter, stream=logging.StreamHandler())
logger = logging.getLogger()
print("*******************************")
print("Debug-log-level is {}".format(debug_log_level))
print("*******************************")
logger.setLevel(debug_log_level)
try:
if not os.path.isdir(logs_folder_path):
Expand All @@ -249,7 +291,7 @@ def main(context, config_folder_path, logs_folder_path, debug_log_level):
except Exception as e:
logger.warning("log folder or log file could not be created or accessed. check folder and file permissions or create the logs folder somewhere you have access with a start option like '--log-folder-path=./logs'")
logging.critical(e, exc_info=True)
cbpi_cli = CraftBeerPiCli(ConfigFolder(config_folder_path, logs_folder_path))
cbpi_cli = CraftBeerPiCli(config)
context.obj = cbpi_cli

@main.command()
Expand All @@ -263,11 +305,15 @@ def setup(context):
@click.option('--list', is_flag=True, help="List all 1Wire Devices")
@click.option('--setup', is_flag=True, help="Setup 1Wire on Raspberry Pi")
def onewire(context, list, setup):
'''Setup 1wire on Raspberry Pi'''
if setup is True:
context.obj.setup_one_wire()
if list is True:
context.obj.list_one_wire()
'''(--setup | --list) Setup 1wire on Raspberry Pi or list sensors'''
operationsystem= sys.platform
if not operationsystem.startswith('win'):
if setup is True:
context.obj.setup_one_wire()
if list is True:
context.obj.list_one_wire()
else:
print("Onewire options NOT available under Windows")

@main.command()
@click.pass_context
Expand Down Expand Up @@ -297,12 +343,20 @@ def create(context, pluginname=[]):
@click.argument('name')
def autostart(context, name):
'''(on|off|status) Enable or disable autostart'''
context.obj.autostart(name)
operationsystem= sys.platform
if not operationsystem.startswith('win'):
context.obj.autostart(name)
else:
print("Autostart option NOT available under Windows")


@main.command()
@click.pass_context
@click.argument('name')
def chromium(context, name):
'''(on|off|status) Enable or disable Kiosk mode'''
context.obj.chromium(name)
operationsystem= sys.platform
if not operationsystem.startswith('win'):
context.obj.chromium(name)
else:
print("Chromium option NOT available under Windows")
2 changes: 1 addition & 1 deletion cbpi/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version: 4.0.8
index_url: /cbpi_ui/static/index.html

port: 8000

debug-log-level: 30
mqtt: false
mqtt_host: localhost
mqtt_port: 1883
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Description=Craftbeer Pi

[Service]
WorkingDirectory=/home/pi
ExecStart=/usr/local/bin/cbpi start
WorkingDirectory=/home/{{ user }}
ExecStart={{ path }} start

[Install]
WantedBy=multi-user.target
19 changes: 12 additions & 7 deletions cbpi/configFolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def check_for_setup(self):
#['fermenter_data.json', 'file'], created by fermentation_controller @ start if not available
#['step_data.json', 'file'], created by step_controller @ start if not available
['config.json', 'file'],
['craftbeerpi.service', 'file'],
['craftbeerpi.template', 'file'],
['chromium.desktop', 'file'],
['dashboard', 'folder'],
['dashboard/widgets', 'folder'],
Expand All @@ -106,7 +106,7 @@ def check_for_setup(self):
]
for checking in required_config_content:
if self.inform_missing_content(self.check_for_file_or_folder(os.path.join(self.configFolderPath, checking[0]), checking[1])):
# since there is no complete config we now check if the config folde rmay be completely empty to show hints:
# since there is no complete config we now check if the config folder may be completely empty to show hints:
if len(os.listdir(os.path.join(self.configFolderPath))) == 0 :
print("***************************************************")
print(f"the config folder '{self.configFolderPath}' seems to be completely empty")
Expand All @@ -118,7 +118,7 @@ def check_for_setup(self):
print("***************************************************")
return False

# if cbpi_dashboard_1.json doesnt exist at the new location (configFolderPath/dashboard)
# if cbpi_dashboard_1.json does'nt exist at the new location (configFolderPath/dashboard)
# we move every cbpi_dashboard_n.json file from the old location (configFolderPath) there.
# this could be a config zip file restore from version 4.0.7.a4 or prior.
dashboard_1_path = os.path.join(self.configFolderPath, 'dashboard', 'cbpi_dashboard_1.json')
Expand All @@ -132,7 +132,7 @@ def check_for_empty_dashboard_1(self, dashboard_1_path):
try:
with open(dashboard_1_path, 'r') as f:
data = json.load(f)
if (len(data['elements']) == 0): # there may exist some pathes but pathes without elements in dashboard is not very likely
if (len(data['elements']) == 0): # there may exist some paths but paths without elements in dashboard is not very likely
return True
else:
return False
Expand All @@ -142,6 +142,11 @@ def check_for_empty_dashboard_1(self, dashboard_1_path):
def inform_missing_content(self, whatsmissing : str):
if whatsmissing == "":
return False
# Starting with cbpi 4.2.0, the craftbeerpi.service file will be created dynamically from the template file based on the user id.
# Therefore, the service file is replaced with a template file in the config folder
if whatsmissing.find("craftbeerpi.template"):
self.copyDefaultFileIfNotExists("craftbeerpi.template")
return False
print("***************************************************")
print(f"CraftBeerPi config content not found: {whatsmissing}")
print("Please run 'cbpi setup' before starting the server ")
Expand Down Expand Up @@ -181,7 +186,7 @@ def create_config_file(self):
self.copyDefaultFileIfNotExists("fermenter_data.json")
self.copyDefaultFileIfNotExists("step_data.json")
self.copyDefaultFileIfNotExists("config.json")
self.copyDefaultFileIfNotExists("craftbeerpi.service")
self.copyDefaultFileIfNotExists("craftbeerpi.template")
self.copyDefaultFileIfNotExists("chromium.desktop")

print("Config Folder created")
Expand All @@ -206,5 +211,5 @@ def recursive_chown(self, path, owner, group):
shutil.chown(os.path.join(dirpath, filename), owner, group)
except:
print("problems assigning file or folder permissions")
print("if this happend on windows its fine")
print("if this happend in the dev container running inside windows its also fine but you might have to rebuild the container if you run into further problems")
print("if this happened on windows its fine")
print("if this happened in the dev container running inside windows its also fine but you might have to rebuild the container if you run into further problems")
10 changes: 9 additions & 1 deletion cbpi/controller/dashboard_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,19 @@ async def get_dashboard_numbers(self):
async def get_current_dashboard(self):
current_dashboard_number = self.cbpi.config.get("current_dashboard_number", 1)
return current_dashboard_number

async def set_current_dashboard(self, dashboard_id=1):
await self.cbpi.config.set("current_dashboard_number", dashboard_id)
return {"status": "OK"}

async def get_current_grid(self):
current_grid = self.cbpi.config.get("current_grid", 5)
return current_grid

async def set_current_grid(self, grid_width=5):
await self.cbpi.config.set("current_grid", grid_width)
return {"status": "OK"}

async def get_slow_pipe_animation(self):
slow_pipe_animation = self.cbpi.config.get("slow_pipe_animation", "Yes")
return slow_pipe_animation
4 changes: 2 additions & 2 deletions cbpi/controller/system_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ async def systeminfo(self):
for nic, addrs in ethernet.items():
if nic == "eth0":
for addr in addrs:
if str(addr.family) == "AddressFamily.AF_INET":
if str(addr.family) == "AddressFamily.AF_INET" or str(addr.family) == "2":
if addr.address:
eth0IP = addr.address
if nic == "wlan0":
for addr in addrs:
if str(addr.family) == "AddressFamily.AF_INET":
if str(addr.family) == "AddressFamily.AF_INET" or str(addr.family) == "2":
if addr.address:
wlan0IP = addr.address
info = psutil.net_if_stats()
Expand Down
Loading

0 comments on commit 42d8a6c

Please sign in to comment.