Repackage to latest boilerplate.

This commit is contained in:
Phil Howard
2023-11-17 09:11:10 +00:00
parent 2b0c8aefd7
commit bebe4504ed
28 changed files with 541 additions and 309 deletions

View File

@@ -1,70 +1,60 @@
LIBRARY_VERSION=$(shell grep version library/setup.cfg | awk -F" = " '{print $$2}') LIBRARY_NAME := $(shell hatch project metadata name 2> /dev/null)
LIBRARY_NAME=$(shell grep name library/setup.cfg | awk -F" = " '{print $$2}') LIBRARY_VERSION := $(shell hatch version 2> /dev/null)
.PHONY: usage install uninstall .PHONY: usage install uninstall check pytest qa build-deps check tag wheel sdist clean dist testdeploy deploy
usage: usage:
ifdef LIBRARY_NAME
@echo "Library: ${LIBRARY_NAME}" @echo "Library: ${LIBRARY_NAME}"
@echo "Version: ${LIBRARY_VERSION}\n" @echo "Version: ${LIBRARY_VERSION}\n"
else
@echo "WARNING: You should 'make dev-deps'\n"
endif
@echo "Usage: make <target>, where target is one of:\n" @echo "Usage: make <target>, where target is one of:\n"
@echo "install: install the library locally from source" @echo "install: install the library locally from source"
@echo "uninstall: uninstall the local library" @echo "uninstall: uninstall the local library"
@echo "check: peform basic integrity checks on the codebase" @echo "dev-deps: install Python dev dependencies"
@echo "python-readme: generate library/README.rst from README.md" @echo "check: perform basic integrity checks on the codebase"
@echo "python-wheels: build python .whl files for distribution" @echo "qa: run linting and package QA"
@echo "python-sdist: build python source distribution" @echo "pytest: run Python test fixtures"
@echo "python-clean: clean python build and dist directories" @echo "clean: clean Python build and dist directories"
@echo "python-dist: build all python distribution files" @echo "build: build Python distribution files"
@echo "python-testdeploy: build all and deploy to test PyPi" @echo "testdeploy: build and upload to test PyPi"
@echo "tag: tag the repository with the current version" @echo "deploy: build and upload to PyPi"
@echo "tag: tag the repository with the current version\n"
install: install:
./install.sh ./install.sh --unstable
uninstall: uninstall:
./uninstall.sh ./uninstall.sh
dev-deps:
python3 -m pip install -r requirements-dev.txt
sudo apt install dos2unix
check: check:
@echo "Checking for trailing whitespace" @bash check.sh
@! grep -IUrn --color "[[:blank:]]$$" --exclude-dir=sphinx --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO
@echo "Checking for DOS line-endings" qa:
@! grep -lIUrn --color " tox -e qa
" --exclude-dir=sphinx --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile
@echo "Checking library/CHANGELOG.txt" pytest:
@cat library/CHANGELOG.txt | grep ^${LIBRARY_VERSION} tox -e py
@echo "Checking library/${LIBRARY_NAME}/__init__.py"
nopost:
@bash check.sh --nopost
tag: tag:
git tag -a "v${LIBRARY_VERSION}" -m "Version ${LIBRARY_VERSION}" git tag -a "v${LIBRARY_VERSION}" -m "Version ${LIBRARY_VERSION}"
build: check
@hatch build
clean:
-rm -r dist
testdeploy: build
library/README.md: README.md library/CHANGELOG.txt twine upload --repository testpypi dist/*
cp README.md library/README.md
printf "\n# Changelog\n" >> library/README.md
deploy: nopost build
library/LICENSE.txt: LICENSE twine upload dist/*
cp LICENSE library/LICENSE.txt
python-wheels: python-readme python-license
cd library; python3 setup.py bdist_wheel
cd library; python setup.py bdist_wheel
python-sdist: python-readme python-license
cd library; python setup.py sdist
python-clean:
-rm -r library/dist
-rm -r library/build
-rm -r library/*.egg-info
python-dist: python-clean python-wheels python-sdist
ls library/dist
python-testdeploy: python-dist
twine upload --repository-url https://test.pypi.org/legacy/ library/dist/*
python-deploy: check python-dist

View File

@@ -2,10 +2,10 @@
Designed as a tiny valet for your plants, Grow HAT mini will monitor the soil moiture for up to 3 plants, water them with tiny pumps, and show you their health on its small but informative screen. Learn more - https://shop.pimoroni.com/products/grow Designed as a tiny valet for your plants, Grow HAT mini will monitor the soil moiture for up to 3 plants, water them with tiny pumps, and show you their health on its small but informative screen. Learn more - https://shop.pimoroni.com/products/grow
[![Build Status](https://travis-ci.com/pimoroni/enviroplus-python.svg?branch=master)](https://travis-ci.com/pimoroni/grow-python) [![Build Status](https://img.shields.io/github/actions/workflow/status/pimoroni/grow-python/test.yml?branch=main)](https://github.com/pimoroni/grow-python/actions/workflows/test.yml)
[![Coverage Status](https://coveralls.io/repos/github/pimoroni/grow-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/grow-python?branch=master) [![Coverage Status](https://coveralls.io/repos/github/pimoroni/grow-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/grow-python?branch=master)
[![PyPi Package](https://img.shields.io/pypi/v/enviroplus.svg)](https://pypi.python.org/pypi/growhat) [![PyPi Package](https://img.shields.io/pypi/v/growhat.svg)](https://pypi.python.org/pypi/growhat)
[![Python Versions](https://img.shields.io/pypi/pyversions/enviroplus.svg)](https://pypi.python.org/pypi/growhat) [![Python Versions](https://img.shields.io/pypi/pyversions/growhat.svg)](https://pypi.python.org/pypi/growhat)
# Installing # Installing
@@ -55,3 +55,14 @@ You should read the following to get up and running with our monitoring script:
* GPIO Pinout - https://pinout.xyz/pinout/grow_hat_mini * GPIO Pinout - https://pinout.xyz/pinout/grow_hat_mini
* Support forums - http://forums.pimoroni.com/c/support * Support forums - http://forums.pimoroni.com/c/support
* Discord - https://discord.gg/hr93ByC * Discord - https://discord.gg/hr93ByC
# Changelog
0.0.2
-----
* Add mutually exclusive locking to pumps to avoid brownout running multiple pumps at once
0.0.1
-----
* Initial Release

88
check.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
# This script handles some basic QA checks on the source
NOPOST=$1
LIBRARY_NAME=`hatch project metadata name`
LIBRARY_VERSION=`hatch version | awk -F "." '{print $1"."$2"."$3}'`
POST_VERSION=`hatch version | awk -F "." '{print substr($4,0,length($4))}'`
TERM=${TERM:="xterm-256color"}
success() {
echo -e "$(tput setaf 2)$1$(tput sgr0)"
}
inform() {
echo -e "$(tput setaf 6)$1$(tput sgr0)"
}
warning() {
echo -e "$(tput setaf 1)$1$(tput sgr0)"
}
while [[ $# -gt 0 ]]; do
K="$1"
case $K in
-p|--nopost)
NOPOST=true
shift
;;
*)
if [[ $1 == -* ]]; then
printf "Unrecognised option: $1\n";
exit 1
fi
POSITIONAL_ARGS+=("$1")
shift
esac
done
inform "Checking $LIBRARY_NAME $LIBRARY_VERSION\n"
inform "Checking for trailing whitespace..."
grep -IUrn --color "[[:blank:]]$" --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=PKG-INFO
if [[ $? -eq 0 ]]; then
warning "Trailing whitespace found!"
exit 1
else
success "No trailing whitespace found."
fi
printf "\n"
inform "Checking for DOS line-endings..."
grep -lIUrn --color $'\r' --exclude-dir=dist --exclude-dir=.tox --exclude-dir=.git --exclude=Makefile
if [[ $? -eq 0 ]]; then
warning "DOS line-endings found!"
exit 1
else
success "No DOS line-endings found."
fi
printf "\n"
inform "Checking CHANGELOG.md..."
cat CHANGELOG.md | grep ^${LIBRARY_VERSION} > /dev/null 2>&1
if [[ $? -eq 1 ]]; then
warning "Changes missing for version ${LIBRARY_VERSION}! Please update CHANGELOG.md."
exit 1
else
success "Changes found for version ${LIBRARY_VERSION}."
fi
printf "\n"
inform "Checking for git tag ${LIBRARY_VERSION}..."
git tag -l | grep -E "${LIBRARY_VERSION}$"
if [[ $? -eq 1 ]]; then
warning "Missing git tag for version ${LIBRARY_VERSION}"
fi
printf "\n"
if [[ $NOPOST ]]; then
inform "Checking for .postN on library version..."
if [[ "$POST_VERSION" != "" ]]; then
warning "Found .$POST_VERSION on library version."
inform "Please only use these for testpypi releases."
exit 1
else
success "OK"
fi
fi

View File

@@ -1,10 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import ST7735
from PIL import Image, ImageDraw, ImageFont
from fonts.ttf import RobotoMedium as UserFont
import logging import logging
import ST7735
from fonts.ttf import RobotoMedium as UserFont
from PIL import Image, ImageDraw, ImageFont
logging.basicConfig( logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s", format="%(asctime)s.%(msecs)03d %(levelname)-8s %(message)s",
level=logging.INFO, level=logging.INFO,

View File

@@ -2,7 +2,6 @@ import time
from grow.moisture import Moisture from grow.moisture import Moisture
print("""moisture.py - Print out sensor reading in Hz print("""moisture.py - Print out sensor reading in Hz
Press Ctrl+C to exit! Press Ctrl+C to exit!

View File

@@ -10,15 +10,14 @@ import time
import ltr559 import ltr559
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
import ST7735 import ST7735
import yaml
from fonts.ttf import RobotoMedium as UserFont from fonts.ttf import RobotoMedium as UserFont
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
import yaml
from grow import Piezo from grow import Piezo
from grow.moisture import Moisture from grow.moisture import Moisture
from grow.pump import Pump from grow.pump import Pump
FPS = 10 FPS = 10
BUTTONS = [5, 6, 16, 24] BUTTONS = [5, 6, 16, 24]

View File

@@ -1,15 +1,14 @@
import time
import logging import logging
import time
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
from PIL import Image, ImageDraw, ImageFont
from fonts.ttf import RobotoMedium as UserFont
import ST7735 import ST7735
from fonts.ttf import RobotoMedium as UserFont
from PIL import Image, ImageDraw, ImageFont
from grow.moisture import Moisture from grow.moisture import Moisture
from grow.pump import Pump from grow.pump import Pump
""" """
Auto water a single target with the channel/pump selected below. Auto water a single target with the channel/pump selected below.

View File

@@ -3,10 +3,12 @@
License: MIT License: MIT
Description: Web API for moisture readings: http://<your-pi-host>:8080/ Description: Web API for moisture readings: http://<your-pi-host>:8080/
""" """
from functools import partial
import json import json
import logging import logging
from functools import partial
from aiohttp import web from aiohttp import web
from grow.moisture import Moisture from grow.moisture import Moisture
json_response = partial(web.json_response, dumps=partial(json.dumps, default=str)) json_response = partial(web.json_response, dumps=partial(json.dumps, default=str))

View File

@@ -1,8 +1,9 @@
__version__ = '0.0.2' __version__ = '0.0.2'
import time
import atexit import atexit
import threading import threading
import time
import RPi.GPIO as GPIO import RPi.GPIO as GPIO

View File

@@ -1,4 +1,5 @@
import time import time
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
MOISTURE_1_PIN = 23 MOISTURE_1_PIN = 23

View File

@@ -1,6 +1,7 @@
import time
import atexit import atexit
import threading import threading
import time
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
PUMP_1_PIN = 17 PUMP_1_PIN = 17

View File

@@ -1,31 +1,31 @@
#!/bin/bash #!/bin/bash
LIBRARY_NAME=`grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}'`
CONFIG=/boot/config.txt MODULE_NAME="grow"
CONFIG_FILE=config.txt
CONFIG_DIR="/boot/firmware"
DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"` DATESTAMP=`date "+%Y-%m-%d-%H-%M-%S"`
CONFIG_BACKUP=false CONFIG_BACKUP=false
APT_HAS_UPDATED=false APT_HAS_UPDATED=false
USER_HOME=/home/$SUDO_USER RESOURCES_TOP_DIR=$HOME/Pimoroni
RESOURCES_TOP_DIR=$USER_HOME/Pimoroni VENV_BASH_SNIPPET=$RESOURCES_DIR/auto_venv.sh
VENV_DIR=$HOME/.virtualenvs/pimoroni
WD=`pwd` WD=`pwd`
USAGE="sudo ./install.sh (--unstable)" USAGE="./install.sh (--unstable)"
POSITIONAL_ARGS=() POSITIONAL_ARGS=()
FORCE=false
UNSTABLE=false UNSTABLE=false
CODENAME=`lsb_release -sc` PYTHON="python"
if [[ $CODENAME == "bullseye" ]]; then
bash ./install-bullseye.sh $@
exit $?
fi
user_check() { user_check() {
if [ $(id -u) -ne 0 ]; then if [ $(id -u) -eq 0 ]; then
printf "Script must be run as root. Try 'sudo ./install.sh'\n" printf "Script should not be run as root. Try './install.sh'\n"
exit 1 exit 1
fi fi
} }
confirm() { confirm() {
if [ "$FORCE" == '-y' ]; then if $FORCE; then
true true
else else
read -r -p "$1 [y/N] " response < /dev/tty read -r -p "$1 [y/N] " response < /dev/tty
@@ -58,16 +58,72 @@ warning() {
echo -e "$(tput setaf 1)$1$(tput sgr0)" echo -e "$(tput setaf 1)$1$(tput sgr0)"
} }
find_config() {
if [ ! -f "$CONFIG_DIR/$CONFIG_FILE" ]; then
CONFIG_DIR="/boot"
if [ ! -f "$CONFIG_DIR/$CONFIG_FILE"]; then
warning "Could not find $CONFIG_FILE!"
exit 1
fi
else
if [ -f "/boot/$CONFIG_FILE" ] && [ ! -L "/boot/$CONFIG_FILE" ]; then
warning "Oops! It looks like /boot/$CONFIG_FILE is not a link to $CONFIG_DIR/$CONFIG_FILE"
warning "You might want to fix this!"
fi
fi
inform "Using $CONFIG_FILE in $CONFIG_DIR"
}
venv_bash_snippet() {
if [ ! -f $VENV_BASH_SNIPPET ]; then
cat << EOF > $VENV_BASH_SNIPPET
# Add `source $RESOURCES_DIR/auto_venv.sh` to your ~/.bashrc to activate
# the Pimoroni virtual environment automagically!
VENV_DIR="$VENV_DIR"
if [ ! -f \$VENV_DIR/bin/activate ]; then
printf "Creating user Python environment in \$VENV_DIR, please wait...\n"
mkdir -p \$VENV_DIR
python3 -m venv --system-site-packages \$VENV_DIR
fi
printf " ↓ ↓ ↓ ↓ Hello, we've activated a Python venv for you. To exit, type \"deactivate\".\n"
source \$VENV_DIR/bin/activate
EOF
fi
}
venv_check() {
PYTHON_BIN=`which $PYTHON`
if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then
printf "This script should be run in a virtual Python environment.\n"
if confirm "Would you like us to create one for you?"; then
if [ ! -f $VENV_DIR/bin/activate ]; then
inform "Creating virtual Python environment in $VENV_DIR, please wait...\n"
mkdir -p $VENV_DIR
/usr/bin/python3 -m venv $VENV_DIR --system-site-packages
venv_bash_snippet
else
inform "Found existing virtual Python environment in $VENV_DIR\n"
fi
inform "Activating virtual Python environment in $VENV_DIR..."
inform "source $VENV_DIR/bin/activate\n"
source $VENV_DIR/bin/activate
else
exit 1
fi
fi
}
function do_config_backup { function do_config_backup {
if [ ! $CONFIG_BACKUP == true ]; then if [ ! $CONFIG_BACKUP == true ]; then
CONFIG_BACKUP=true CONFIG_BACKUP=true
FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt" FILENAME="config.preinstall-$LIBRARY_NAME-$DATESTAMP.txt"
inform "Backing up $CONFIG to /boot/$FILENAME\n" inform "Backing up $CONFIG_DIR/$CONFIG_FILE to $CONFIG_DIR/$FILENAME\n"
cp $CONFIG /boot/$FILENAME sudo cp $CONFIG_DIR/$CONFIG_FILE $CONFIG_DIR/$FILENAME
mkdir -p $RESOURCES_TOP_DIR/config-backups/ mkdir -p $RESOURCES_TOP_DIR/config-backups/
cp $CONFIG $RESOURCES_TOP_DIR/config-backups/$FILENAME cp $CONFIG_DIR/$CONFIG_FILE $RESOURCES_TOP_DIR/config-backups/$FILENAME
if [ -f "$UNINSTALLER" ]; then if [ -f "$UNINSTALLER" ]; then
echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG" >> $UNINSTALLER echo "cp $RESOURCES_TOP_DIR/config-backups/$FILENAME $CONFIG_DIR/$CONFIG_FILE" >> $UNINSTALLER
fi fi
fi fi
} }
@@ -88,16 +144,20 @@ function apt_pkg_install {
if ! [ "$PACKAGES" == "" ]; then if ! [ "$PACKAGES" == "" ]; then
echo "Installing missing packages: $PACKAGES" echo "Installing missing packages: $PACKAGES"
if [ ! $APT_HAS_UPDATED ]; then if [ ! $APT_HAS_UPDATED ]; then
apt update sudo apt update
APT_HAS_UPDATED=true APT_HAS_UPDATED=true
fi fi
apt install -y $PACKAGES sudo apt install -y $PACKAGES
if [ -f "$UNINSTALLER" ]; then if [ -f "$UNINSTALLER" ]; then
echo "apt uninstall -y $PACKAGES" echo "apt uninstall -y $PACKAGES" >> $UNINSTALLER
fi fi
fi fi
} }
function pip_pkg_install {
PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring $PYTHON -m pip install --upgrade "$@"
}
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
K="$1" K="$1"
case $K in case $K in
@@ -105,6 +165,15 @@ while [[ $# -gt 0 ]]; do
UNSTABLE=true UNSTABLE=true
shift shift
;; ;;
-f|--force)
FORCE=true
shift
;;
-p|--python)
PYTHON=$2
shift
shift
;;
*) *)
if [[ $1 == -* ]]; then if [[ $1 == -* ]]; then
printf "Unrecognised option: $1\n"; printf "Unrecognised option: $1\n";
@@ -117,28 +186,31 @@ while [[ $# -gt 0 ]]; do
done done
user_check user_check
venv_check
apt_pkg_install python-configparser if [ ! -f `which $PYTHON` ]; then
printf "Python path $PYTHON not found!\n"
exit 1
fi
CONFIG_VARS=`python - <<EOF PYTHON_VER=`$PYTHON --version`
from configparser import ConfigParser
c = ConfigParser() printf "$LIBRARY_NAME Python Library: Installer\n\n"
c.read('library/setup.cfg')
p = dict(c['pimoroni']) inform "Checking Dependencies. Please wait..."
# Convert multi-line config entries into bash arrays
for k in p.keys(): pip_pkg_install toml
fmt = '"{}"'
if '\n' in p[k]: CONFIG_VARS=`$PYTHON - <<EOF
p[k] = "'\n\t'".join(p[k].split('\n')[1:]) import toml
fmt = "('{}')" config = toml.load("pyproject.toml")
p[k] = fmt.format(p[k]) p = dict(config['tool']['pimoroni'])
# Convert list config entries into bash arrays
for k, v in p.items():
v = "'\n\t'".join(v)
p[k] = f"('{v}')"
print(""" print("""
LIBRARY_NAME="{name}" APT_PACKAGES={apt_packages}
LIBRARY_VERSION="{version}"
""".format(**c['metadata']))
print("""
PY3_DEPS={py3deps}
PY2_DEPS={py2deps}
SETUP_CMDS={commands} SETUP_CMDS={commands}
CONFIG_TXT={configtxt} CONFIG_TXT={configtxt}
""".format(**p)) """.format(**p))
@@ -154,6 +226,13 @@ eval $CONFIG_VARS
RESOURCES_DIR=$RESOURCES_TOP_DIR/$LIBRARY_NAME RESOURCES_DIR=$RESOURCES_TOP_DIR/$LIBRARY_NAME
UNINSTALLER=$RESOURCES_DIR/uninstall.sh UNINSTALLER=$RESOURCES_DIR/uninstall.sh
RES_DIR_OWNER=`stat -c "%U" $RESOURCES_TOP_DIR`
if [[ "$RES_DIR_OWNER" == "root" ]]; then
warning "\n\nFixing $RESOURCES_TOP_DIR permissions!\n\n"
sudo chown -R $USER:$USER $RESOURCES_TOP_DIR
fi
mkdir -p $RESOURCES_DIR mkdir -p $RESOURCES_DIR
cat << EOF > $UNINSTALLER cat << EOF > $UNINSTALLER
@@ -161,50 +240,35 @@ printf "It's recommended you run these steps manually.\n"
printf "If you want to run the full script, open it in\n" printf "If you want to run the full script, open it in\n"
printf "an editor and remove 'exit 1' from below.\n" printf "an editor and remove 'exit 1' from below.\n"
exit 1 exit 1
source $VIRTUAL_ENV/bin/activate
EOF EOF
printf "$LIBRARY_NAME $LIBRARY_VERSION Python Library: Installer\n\n"
if $UNSTABLE; then if $UNSTABLE; then
warning "Installing unstable library from source.\n\n" warning "Installing unstable library from source.\n\n"
else else
printf "Installing stable library from pypi.\n\n" printf "Installing stable library from pypi.\n\n"
fi fi
cd library inform "Installing for $PYTHON_VER...\n"
apt_pkg_install "${APT_PACKAGES[@]}"
printf "Installing for Python 2..\n"
apt_pkg_install "${PY2_DEPS[@]}"
if $UNSTABLE; then if $UNSTABLE; then
python setup.py install > /dev/null pip_pkg_install .
else else
pip install --upgrade $LIBRARY_NAME pip_pkg_install $LIBRARY_NAME
fi fi
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
success "Done!\n" success "Done!\n"
echo "pip uninstall $LIBRARY_NAME" >> $UNINSTALLER echo "$PYTHON -m pip uninstall $LIBRARY_NAME" >> $UNINSTALLER
fi
if [ -f "/usr/bin/python3" ]; then
printf "Installing for Python 3..\n"
apt_pkg_install "${PY3_DEPS[@]}"
if $UNSTABLE; then
python3 setup.py install > /dev/null
else
pip3 install --upgrade $LIBRARY_NAME
fi
if [ $? -eq 0 ]; then
success "Done!\n"
echo "pip3 uninstall $LIBRARY_NAME" >> $UNINSTALLER
fi
fi fi
cd $WD cd $WD
find_config
for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do for ((i = 0; i < ${#SETUP_CMDS[@]}; i++)); do
CMD="${SETUP_CMDS[$i]}" CMD="${SETUP_CMDS[$i]}"
# Attempt to catch anything that touches /boot/config.txt and trigger a backup # Attempt to catch anything that touches config.txt and trigger a backup
if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG"* ]] || [[ "$CMD" == *"\$CONFIG"* ]]; then if [[ "$CMD" == *"raspi-config"* ]] || [[ "$CMD" == *"$CONFIG_DIR/$CONFIG_FILE"* ]] || [[ "$CMD" == *"\$CONFIG_DIR/\$CONFIG_FILE"* ]]; then
do_config_backup do_config_backup
fi fi
eval $CMD eval $CMD
@@ -214,10 +278,10 @@ for ((i = 0; i < ${#CONFIG_TXT[@]}; i++)); do
CONFIG_LINE="${CONFIG_TXT[$i]}" CONFIG_LINE="${CONFIG_TXT[$i]}"
if ! [ "$CONFIG_LINE" == "" ]; then if ! [ "$CONFIG_LINE" == "" ]; then
do_config_backup do_config_backup
inform "Adding $CONFIG_LINE to $CONFIG\n" inform "Adding $CONFIG_LINE to $CONFIG_DIR/$CONFIG_FILE\n"
sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG sudo sed -i "s/^#$CONFIG_LINE/$CONFIG_LINE/" $CONFIG_DIR/$CONFIG_FILE
if ! grep -q "^$CONFIG_LINE" $CONFIG; then if ! grep -q "^$CONFIG_LINE" $CONFIG_DIR/$CONFIG_FILE; then
printf "$CONFIG_LINE\n" >> $CONFIG printf "$CONFIG_LINE\n" | sudo tee --append $CONFIG_DIR/$CONFIG_FILE
fi fi
fi fi
done done
@@ -231,14 +295,17 @@ if [ -d "examples" ]; then
fi fi
fi fi
if [ -d "service" ]; then printf "\n"
inform "Grow includes a service that runs on boot and monitors your plants."
if confirm "Would you like to install the service?"; then if confirm "Would you like to generate documentation?"; then
cd service pip_pkg_install pdoc
sudo ./install.sh printf "Generating documentation.\n"
echo "rm /usr/bin/grow" >> $UNINSTALLER $PYTHON -m pdoc $MODULE_NAME -o $RESOURCES_DIR/docs > /dev/null
echo "rm -r /usr/share/grow-monitor" >> $UNINSTALLER if [ $? -eq 0 ]; then
echo "rm /etc/default/grow" >> $UNINSTALLER inform "Documentation saved to $RESOURCES_DIR/docs"
success "Done!"
else
warning "Error: Failed to generate documentation."
fi fi
fi fi

View File

@@ -1,4 +0,0 @@
[run]
source = grow
omit =
.tox/*

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Pimoroni Ltd.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,68 +0,0 @@
# Grow HAT Mini
Designed as a tiny valet for your plants, Grow HAT mini will monitor the soil moiture for up to 3 plants, water them with tiny pumps, and show you their health on its small but informative screen. Learn more - https://shop.pimoroni.com/products/grow
[![Build Status](https://travis-ci.com/pimoroni/enviroplus-python.svg?branch=master)](https://travis-ci.com/pimoroni/grow-python)
[![Coverage Status](https://coveralls.io/repos/github/pimoroni/grow-python/badge.svg?branch=master)](https://coveralls.io/github/pimoroni/grow-python?branch=master)
[![PyPi Package](https://img.shields.io/pypi/v/enviroplus.svg)](https://pypi.python.org/pypi/growhat)
[![Python Versions](https://img.shields.io/pypi/pyversions/enviroplus.svg)](https://pypi.python.org/pypi/growhat)
# Installing
You're best using the "One-line" install method.
## One-line (Installs from GitHub)
```
curl -sSL https://get.pimoroni.com/grow | bash
```
**Note** report issues with one-line installer here: https://github.com/pimoroni/get
## Or... Install and configure dependencies from GitHub:
* `git clone https://github.com/pimoroni/grow-python`
* `cd grow-python`
* `sudo ./install.sh`
**Note** Raspbian Lite users may first need to install git: `sudo apt install git`
## Or... Install from PyPi and configure manually:
* Install dependencies:
```
sudo apt install python3-setuptools python3-pip python3-yaml python3-smbus python3-pil python3-spidev python3-rpi.gpio
```
* Run `sudo pip3 install growhat`
**Note** this wont perform any of the required configuration changes on your Pi, you may additionally need to:
* Enable i2c: `sudo raspi-config nonint do_i2c 0`
* Enable SPI: `sudo raspi-config nonint do_spi 0`
* Add the following to `/boot/config.txt`: `dtoverlay=spi0-cs,cs0_pin=14`
## Monitoring
You should read the following to get up and running with our monitoring script:
* [Using and configuring monitor.py](examples/README.md)
* [Setting up monitor.py as a service](service/README.md)
## Help & Support
* GPIO Pinout - https://pinout.xyz/pinout/grow_hat_mini
* Support forums - http://forums.pimoroni.com/c/support
* Discord - https://discord.gg/hr93ByC
# Changelog
0.0.2
-----
* Add mutually exclusive locking to pumps to avoid brownout running multiple pumps at once
0.0.1
-----
* Initial Release

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env python
"""
Copyright (c) 2020 Pimoroni
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from setuptools import setup
setup()

View File

@@ -1,24 +0,0 @@
[tox]
envlist = py,qa
skip_missing_interpreters = True
[testenv]
commands =
python setup.py install
coverage run -m pytest -v -r wsx
coverage report
deps =
mock
pytest>=3.1
pytest-cov
[testenv:qa]
commands =
check-manifest --ignore tox.ini,tests/*,.coveragerc
python setup.py sdist bdist_wheel
twine check dist/*
flake8 --ignore E501
deps =
check-manifest
flake8
twine

124
pyproject.toml Normal file
View File

@@ -0,0 +1,124 @@
[build-system]
requires = ["hatchling", "hatch-fancy-pypi-readme"]
build-backend = "hatchling.build"
[project]
name = "growhat"
dynamic = ["version", "readme"]
description = "Grow HAT Mini. A plant valet add-on for the Raspberry Pi"
license = {file = "LICENSE"}
requires-python = ">= 3.7"
authors = [
{ name = "Philip Howard", email = "phil@pimoroni.com" },
{ name = "Paul Beech", email = "paul@pimoroni.com" },
]
maintainers = [
{ name = "Philip Howard", email = "phil@pimoroni.com" },
]
keywords = [
"Pi",
"Raspberry",
]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Software Development",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
]
dependencies = [
"ltr559",
"st7735>=0.0.5",
"pyyaml",
"fonts",
"font-roboto"
]
[project.urls]
GitHub = "https://www.github.com/pimoroni/grow-python"
Homepage = "https://www.pimoroni.com"
[tool.hatch.version]
path = "grow/__init__.py"
[tool.hatch.build]
include = [
"grow",
"README.md",
"CHANGELOG.md",
"LICENSE"
]
[tool.hatch.build.targets.sdist]
include = [
"*"
]
exclude = [
".*",
"dist"
]
[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"
fragments = [
{ path = "README.md" },
{ text = "\n" },
{ path = "CHANGELOG.md" }
]
[tool.ruff]
exclude = [
'.tox',
'.egg',
'.git',
'__pycache__',
'build',
'dist'
]
line-length = 200
[tool.codespell]
skip = """
./.tox,\
./.egg,\
./.git,\
./__pycache__,\
./build,\
./dist.\
"""
[tool.isort]
line_length = 200
[tool.black]
line-length = 200
[tool.check-manifest]
ignore = [
'.stickler.yml',
'boilerplate.md',
'check.sh',
'install.sh',
'uninstall.sh',
'Makefile',
'tox.ini',
'tests/*',
'examples/*',
'.coveragerc',
'requirements-dev.txt',
'requirements-examples.txt'
]
[tool.pimoroni]
apt_packages = []
configtxt = []
commands = []

9
requirements-dev.txt Normal file
View File

@@ -0,0 +1,9 @@
check-manifest
ruff
codespell
isort
twine
hatch
hatch-fancy-pypi-readme
tox
pdoc

View File

@@ -0,0 +1,3 @@
pyyaml
pillow>=10.0.0
numpy

View File

@@ -3,6 +3,7 @@ These allow the mocking of various Python modules
that might otherwise have runtime side-effects. that might otherwise have runtime side-effects.
""" """
import sys import sys
import mock import mock
import pytest import pytest
from i2cdevice import MockSMBus from i2cdevice import MockSMBus

View File

@@ -28,7 +28,7 @@ def test_moisture_read(GPIO, smbus):
def test_pump_setup(GPIO, smbus): def test_pump_setup(GPIO, smbus):
from grow.pump import Pump, PUMP_PWM_FREQ from grow.pump import PUMP_PWM_FREQ, Pump
ch1 = Pump(channel=1) ch1 = Pump(channel=1)
ch2 = Pump(channel=2) ch2 = Pump(channel=2)

34
tox.ini Normal file
View File

@@ -0,0 +1,34 @@
[tox]
envlist = py,qa
skip_missing_interpreters = True
isolated_build = true
minversion = 4.0.0
[testenv]
commands =
coverage run -m pytest -v -r wsx
coverage report
deps =
mock
pytest>=3.1
pytest-cov
build
[testenv:qa]
commands =
check-manifest
python -m build --no-isolation
python -m twine check dist/*
isort --check .
ruff .
codespell .
deps =
check-manifest
ruff
codespell
isort
twine
build
hatch
hatch-fancy-pypi-readme

View File

@@ -1,25 +1,72 @@
#!/bin/bash #!/bin/bash
LIBRARY_VERSION=`cat library/setup.cfg | grep version | awk -F" = " '{print $2}'` FORCE=false
LIBRARY_NAME=`cat library/setup.cfg | grep name | awk -F" = " '{print $2}'` LIBRARY_NAME=`grep -m 1 name pyproject.toml | awk -F" = " '{print substr($2,2,length($2)-2)}'`
RESOURCES_DIR=$HOME/Pimoroni/$LIBRARY_NAME
PYTHON="python"
printf "$LIBRARY_NAME $LIBRARY_VERSION Python Library: Uninstaller\n\n"
if [ $(id -u) -ne 0 ]; then venv_check() {
printf "Script must be run as root. Try 'sudo ./uninstall.sh'\n" PYTHON_BIN=`which $PYTHON`
exit 1 if [[ $VIRTUAL_ENV == "" ]] || [[ $PYTHON_BIN != $VIRTUAL_ENV* ]]; then
printf "This script should be run in a virtual Python environment.\n"
exit 1
fi
}
user_check() {
if [ $(id -u) -eq 0 ]; then
printf "Script should not be run as root. Try './uninstall.sh'\n"
exit 1
fi
}
confirm() {
if $FORCE; then
true
else
read -r -p "$1 [y/N] " response < /dev/tty
if [[ $response =~ ^(yes|y|Y)$ ]]; then
true
else
false
fi
fi
}
prompt() {
read -r -p "$1 [y/N] " response < /dev/tty
if [[ $response =~ ^(yes|y|Y)$ ]]; then
true
else
false
fi
}
success() {
echo -e "$(tput setaf 2)$1$(tput sgr0)"
}
inform() {
echo -e "$(tput setaf 6)$1$(tput sgr0)"
}
warning() {
echo -e "$(tput setaf 1)$1$(tput sgr0)"
}
printf "$LIBRARY_NAME Python Library: Uninstaller\n\n"
user_check
venv_check
printf "Uninstalling for Python 3...\n"
$PYTHON -m pip uninstall $LIBRARY_NAME
if [ -d $RESOURCES_DIR ]; then
if confirm "Would you like to delete $RESOURCES_DIR?"; then
rm -r $RESOURCES_DIR
fi
fi fi
cd library
printf "Unnstalling for Python 2..\n"
pip uninstall $LIBRARY_NAME
if [ -f "/usr/bin/pip3" ]; then
printf "Uninstalling for Python 3..\n"
pip3 uninstall $LIBRARY_NAME
fi
cd ..
printf "Done!\n" printf "Done!\n"