mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-08-09 18:52:40 +02:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea5ee44295 | ||
|
|
16ad8daf44 | ||
|
|
67a103d1f3 | ||
|
|
274f282e11 | ||
|
|
4e432e05bd | ||
|
|
eda209422f | ||
|
|
5b47b94833 | ||
|
|
98409d9895 | ||
|
|
433b1c30f1 | ||
|
|
a477cb83a8 | ||
|
|
a22dcba77c | ||
|
|
c1d94a8f61 | ||
|
|
dd64f4ee16 | ||
|
|
1414b1ed3b | ||
|
|
acd404622b | ||
|
|
d657077570 | ||
|
|
0e6da89cfd | ||
|
|
faa2b9d32c | ||
|
|
83699f1933 | ||
|
|
fea3e85053 | ||
|
|
5efa1df350 | ||
|
|
dd5b5f456a | ||
|
|
e0e3aff929 | ||
|
|
2a02979e37 | ||
|
|
1b3042a082 | ||
|
|
211edc1bbc | ||
|
|
0447621895 |
+14
@@ -0,0 +1,14 @@
|
||||
# Dockerfile for development on a pc/mac
|
||||
FROM python:2
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY requirements.txt ./
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "run.py"]
|
||||
@@ -28,6 +28,21 @@ http://web.craftbeerpi.com/hardware/
|
||||
|
||||
CraftBeerPi 3.0 is a complete rewrite. Server as well as user interface. I recommend to use a second SD card for testing.
|
||||
|
||||
## Docker-based development
|
||||
|
||||
For developing this application or its plugins on a PC/Mac you can use the docker-compose file:
|
||||
|
||||
``` shell
|
||||
$ docker-compose up
|
||||
...
|
||||
Starting craftbeerpi3_app_1 ... done
|
||||
Attaching to craftbeerpi3_app_1
|
||||
app_1 | [2018-08-13 12:54:44,264] ERROR in __init__: BUZZER not working
|
||||
app_1 | (1) wsgi starting up on http://0.0.0.0:5000
|
||||
```
|
||||
|
||||
The contents of this folder will be mounted to `/usr/src/craftbeerpi3` and the server will be accesible on `localhost:5000`.
|
||||
|
||||
## Donation
|
||||
|
||||
CraftBeerPi is a free & open source project. If you like to support the project I happy about a donation:
|
||||
|
||||
+2
-1
@@ -84,7 +84,8 @@ INSERT OR IGNORE INTO config VALUES ('actor_cols', 4, 'select', 'Adjust the widt
|
||||
INSERT OR IGNORE INTO config VALUES ('sensor_cols', 4, 'select', 'Adjust the width of a sensor widget on the brewing dashboard', '[1,2,3, 4, 5, 6, 7, 8, 9, 10, 11, 12]');
|
||||
INSERT OR IGNORE INTO config VALUES ('unit', 'C', 'select', 'Temperature Unit', '["C","F"]');
|
||||
INSERT OR IGNORE INTO config VALUES ('brewery_name', 'My Home Brewery', 'text', 'Your brewery name', NULL );
|
||||
INSERT OR IGNORE INTO config VALUES ('buzzer', 16, 'select', 'Buzzer GPIO', '[16,17,18,19,20]');
|
||||
INSERT OR IGNORE INTO config VALUES ('buzzer', 16, 'select', 'Buzzer GPIO', '[16,17,18,19,20,21,22,23]');
|
||||
INSERT OR IGNORE INTO config VALUES ('buzzer_beep_level', 'HIGH', 'select', 'Buzzer Logic Beep Level', '["HIGH", "LOW"]');
|
||||
INSERT OR IGNORE INTO config VALUES ('setup', 'YES', 'select', 'Show the Setup dialog', '["YES","NO"]');
|
||||
INSERT OR IGNORE INTO config VALUES ('brew_name', '', 'text', 'Brew Name', NULL);
|
||||
INSERT OR IGNORE INTO config VALUES ('donation_notification', 'YES', 'select', 'Disable Donation Notification', '["YES","NO"]');
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# docker-compose file for development on a pc/mac
|
||||
version: '3.3'
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
- 5000:5000
|
||||
volumes:
|
||||
- $PWD:/usr/src/app
|
||||
+13
-9
@@ -19,7 +19,8 @@ show_menu () {
|
||||
"7" "Software Update (git pull)" \
|
||||
"8" "Reset File Changes (git reset --hard)" \
|
||||
"9" "Clear all logs" \
|
||||
"10" "Reboot Raspberry Pi" 3>&1 1>&2 2>&3)
|
||||
"10" "Reboot Raspberry Pi" \
|
||||
"11" "Stop CraftBeerPi, Clear logs, Start CraftBeerPi" 3>&1 1>&2 2>&3)
|
||||
|
||||
BUTTON=$?
|
||||
# Exit if user pressed cancel or escape
|
||||
@@ -34,14 +35,6 @@ show_menu () {
|
||||
apt-get -y update; apt-get -y upgrade;
|
||||
fi
|
||||
|
||||
confirmAnswer "Would you like to install wiringPI? This is required to control the GPIO"
|
||||
if [ $? = 0 ]; then
|
||||
git clone git://git.drogon.net/wiringPi;
|
||||
cd wiringPi;
|
||||
./build; cd ..;
|
||||
rm -rf wiringPi;
|
||||
fi
|
||||
|
||||
apt-get -y install python-setuptools
|
||||
easy_install pip
|
||||
apt-get -y install python-dev
|
||||
@@ -143,6 +136,17 @@ show_menu () {
|
||||
show_menu
|
||||
fi
|
||||
;;
|
||||
11)
|
||||
confirmAnswer "Are you sure you want to reboot CraftBeerPi and delete all log files?"
|
||||
if [ $? = 0 ]; then
|
||||
sudo /etc/init.d/craftbeerpiboot stop
|
||||
sudo rm -rf logs/*.log
|
||||
sudo /etc/init.d/craftbeerpiboot start
|
||||
show_menu
|
||||
else
|
||||
show_menu
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -34,7 +34,5 @@ class Hysteresis(KettleController):
|
||||
self.heater_on(100)
|
||||
elif self.get_temp() >= self.get_target_temp() - float(self.off):
|
||||
self.heater_off()
|
||||
else:
|
||||
self.heater_off()
|
||||
self.sleep(1)
|
||||
|
||||
|
||||
@@ -10,10 +10,11 @@ except Exception as e:
|
||||
class Buzzer(object):
|
||||
|
||||
sound = ["H", 0.1, "L", 0.1, "H", 0.1, "L", 0.1, "H", 0.1, "L"]
|
||||
def __init__(self, gpio):
|
||||
def __init__(self, gpio, beep_level):
|
||||
try:
|
||||
cbpi.app.logger.info("INIT BUZZER NOW GPIO%s" % gpio)
|
||||
self.gpio = int(gpio)
|
||||
self.beep_level = beep_level
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(self.gpio, GPIO.OUT)
|
||||
self.state = True
|
||||
@@ -31,10 +32,14 @@ class Buzzer(object):
|
||||
try:
|
||||
for i in sound:
|
||||
if (isinstance(i, str)):
|
||||
if i == "H":
|
||||
if i == "H" and self.beep_level == "HIGH":
|
||||
GPIO.output(int(self.gpio), GPIO.HIGH)
|
||||
else:
|
||||
elif i == "H" and self.beep_level != "HIGH":
|
||||
GPIO.output(int(self.gpio), GPIO.LOW)
|
||||
elif i == "L" and self.beep_level == "HIGH":
|
||||
GPIO.output(int(self.gpio), GPIO.LOW)
|
||||
else:
|
||||
GPIO.output(int(self.gpio), GPIO.HIGH)
|
||||
else:
|
||||
time.sleep(i)
|
||||
except Exception as e:
|
||||
@@ -44,7 +49,9 @@ class Buzzer(object):
|
||||
|
||||
@cbpi.initalizer(order=1)
|
||||
def init(cbpi):
|
||||
gpio = cbpi.get_config_parameter("buzzer", 16)
|
||||
cbpi.buzzer = Buzzer(gpio)
|
||||
gpio = cbpi.get_config_parameter("buzzer", 22)
|
||||
beep_level = cbpi.get_config_parameter("buzzer_beep_level", "HIGH")
|
||||
|
||||
cbpi.buzzer = Buzzer(gpio, beep_level)
|
||||
cbpi.beep()
|
||||
cbpi.app.logger.info("INIT OK")
|
||||
|
||||
@@ -40,7 +40,6 @@ class ActorAPI(object):
|
||||
value = self.cache.get("actors").get(int(id))
|
||||
cfg = value.config.copy()
|
||||
cfg.update(dict(api=self, id=id, name=value.name))
|
||||
cfg.update(dict(api=self, id=id, name=value.name))
|
||||
clazz = self.cache.get("actor_types").get(value.type).get("class")
|
||||
value.instance = clazz(**cfg)
|
||||
value.instance.init()
|
||||
|
||||
@@ -48,6 +48,7 @@ class BeerXMLImport(FlaskView):
|
||||
|
||||
|
||||
steps = self.getSteps(id)
|
||||
boil_time_alerts = self.getBoilAlerts(id)
|
||||
name = self.getRecipeName(id)
|
||||
self.api.set_config_parameter("brew_name", name)
|
||||
boil_time = self.getBoilTime(id)
|
||||
@@ -67,10 +68,29 @@ class BeerXMLImport(FlaskView):
|
||||
for row in steps:
|
||||
Step.insert(**{"name": row.get("name"), "type": mashstep_type, "config": {"kettle": mash_kettle, "temp": float(row.get("temp")), "timer": row.get("timer")}})
|
||||
Step.insert(**{"name": "ChilStep", "type": "ChilStep", "config": {"timer": 15}})
|
||||
## Add cooking step
|
||||
Step.insert(**{"name": "Boil", "type": boilstep_type, "config": {"kettle": boil_kettle, "temp": boil_temp, "timer": boil_time}})
|
||||
## Add boiling step
|
||||
Step.insert(**{
|
||||
"name": "Boil",
|
||||
"type": boilstep_type,
|
||||
"config": {
|
||||
"kettle": boil_kettle,
|
||||
"temp": boil_temp,
|
||||
"timer": boil_time,
|
||||
## Beer XML defines additions as the total time spent in boiling,
|
||||
## CBP defines it as time-until-alert
|
||||
|
||||
## Also, The model supports five boil-time additions.
|
||||
## Set the rest to None to signal them being absent
|
||||
"hop_1": boil_time - boil_time_alerts[0] if len(boil_time_alerts) >= 1 else None,
|
||||
"hop_2": boil_time - boil_time_alerts[1] if len(boil_time_alerts) >= 2 else None,
|
||||
"hop_3": boil_time - boil_time_alerts[2] if len(boil_time_alerts) >= 3 else None,
|
||||
"hop_4": boil_time - boil_time_alerts[3] if len(boil_time_alerts) >= 4 else None,
|
||||
"hop_5": boil_time - boil_time_alerts[4] if len(boil_time_alerts) >= 5 else None
|
||||
}
|
||||
})
|
||||
## Add Whirlpool step
|
||||
Step.insert(**{"name": "Whirlpool", "type": "ChilStep", "config": {"timer": 15}})
|
||||
StepView().reset()
|
||||
self.api.emit("UPDATE_ALL_STEPS", Step.get_all())
|
||||
self.api.notify(headline="Recipe %s loaded successfully" % name, message="")
|
||||
except Exception as e:
|
||||
@@ -87,18 +107,40 @@ class BeerXMLImport(FlaskView):
|
||||
e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
|
||||
return float(e.find('./RECIPE[%s]/BOIL_TIME' % (str(id))).text)
|
||||
|
||||
def getBoilAlerts(self, id):
|
||||
e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
|
||||
|
||||
recipe = e.find('./RECIPE[%s]' % (str(id)))
|
||||
alerts = []
|
||||
for e in recipe.findall('./HOPS/HOP'):
|
||||
use = e.find('USE').text
|
||||
## Hops which are not used in the boil step should not cause alerts
|
||||
if use != 'Aroma' and use != 'Boil':
|
||||
continue
|
||||
|
||||
alerts.append(float(e.find('TIME').text))
|
||||
|
||||
## There might also be miscelaneous additions during boild time
|
||||
for e in recipe.findall('MISCS/MISC[USE="Boil"]'):
|
||||
alerts.append(float(e.find('TIME').text))
|
||||
|
||||
## Dedupe and order the additions by their time, to prevent multiple alerts at the same time
|
||||
alerts = sorted(list(set(alerts)))
|
||||
|
||||
## CBP should have these additions in reverse
|
||||
alerts.reverse()
|
||||
|
||||
return alerts
|
||||
|
||||
def getSteps(self, id):
|
||||
|
||||
|
||||
|
||||
e = xml.etree.ElementTree.parse(self.BEER_XML_FILE).getroot()
|
||||
steps = []
|
||||
for e in e.findall('./RECIPE[%s]/MASH/MASH_STEPS/MASH_STEP' % (str(id))):
|
||||
|
||||
if self.api.get_config_parameter("unit", "C") == "C":
|
||||
temp = float(e.find("STEP_TEMP").text)
|
||||
else:
|
||||
temp = round(9.0 / 5.0 * float(e.find("STEP_TEMP").text) + 32, 2)
|
||||
|
||||
steps.append({"name": e.find("NAME").text, "temp": temp, "timer": float(e.find("STEP_TIME").text)})
|
||||
|
||||
return steps
|
||||
|
||||
File diff suppressed because one or more lines are too long
+3
-3
@@ -1,4 +1,4 @@
|
||||
Flask==0.11.1
|
||||
Flask==0.12.4
|
||||
Flask-SocketIO==2.6.2
|
||||
eventlet==0.19.0
|
||||
greenlet==0.4.10
|
||||
@@ -6,8 +6,8 @@ python-dateutil==2.5.3
|
||||
python-engineio==0.9.2
|
||||
python-mimeparse==1.5.2
|
||||
python-socketio==1.4.4
|
||||
PyYAML==3.11
|
||||
requests==2.11.0
|
||||
PyYAML==4.2b1
|
||||
requests==2.20.0
|
||||
Werkzeug==0.11.10
|
||||
httplib2==0.9.2
|
||||
flask-classy==0.6.10
|
||||
|
||||
Reference in New Issue
Block a user