Skip to content

Commit 04b9b00

Browse files
committed
Fixes broken pin in Airlock and refactor code
1 parent 3469e78 commit 04b9b00

File tree

6 files changed

+380
-367
lines changed

6 files changed

+380
-367
lines changed

pyplaato/const.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
URL = "http://plaato.blynk.cc/{auth_token}/get"
2+
3+
# Units
4+
UNIT_TEMP_CELSIUS = "°C"
5+
UNIT_TEMP_FAHRENHEIT = "°F"
6+
UNIT_PERCENTAGE = "%"
7+
UNIT_BUBBLES_PER_MINUTE = "bpm"

pyplaato/models/airlock.py

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
from enum import Enum
2+
3+
from pyplaato.const import UNIT_PERCENTAGE, UNIT_BUBBLES_PER_MINUTE
4+
from pyplaato.models.device import PlaatoDevice, PlaatoDeviceType
5+
from pyplaato.models.pins import PinsBase
6+
7+
8+
class PlaatoAirlock(PlaatoDevice):
9+
"""Class for holding a Plaato Airlock"""
10+
11+
device_type = PlaatoDeviceType.Airlock
12+
13+
def __init__(self, attrs):
14+
self.bmp = attrs.get(self.Pins.BPM, None)
15+
self.temperature_unit = attrs.get(self.Pins.TEMPERATURE_UNIT, None)
16+
self.volume_unit = attrs.get(self.Pins.VOLUME_UNIT, None)
17+
self.bubbles = attrs.get(self.Pins.BUBBLES, None)
18+
self.batch_volume = attrs.get(self.Pins.BATCH_VOLUME, None)
19+
self.sg = attrs.get(self.Pins.SG, None)
20+
self.og = attrs.get(self.Pins.OG, None)
21+
self.__abv = attrs.get(self.Pins.ABV, None)
22+
self.__co2_volume = attrs.get(self.Pins.CO2_VOLUME, None)
23+
self.__temperature = attrs.get(self.Pins.TEMPERATURE, None)
24+
25+
def __repr__(self):
26+
return (f"{self.__class__.__name__} -> "
27+
f"BMP: {self.bmp}, "
28+
f"Temp: {self.temperature}")
29+
30+
@property
31+
def temperature(self):
32+
if self.__temperature is not None:
33+
return round(float(self.__temperature), 1)
34+
35+
@property
36+
def abv(self):
37+
if self.__abv is not None:
38+
return round(float(self.__abv), 2)
39+
40+
@property
41+
def co2_volume(self):
42+
if self.__co2_volume is not None:
43+
return round(float(self.__co2_volume), 2)
44+
45+
@property
46+
def name(self) -> str:
47+
return "Airlock"
48+
49+
def get_sensor_name(self, pin: PinsBase) -> str:
50+
names = {
51+
self.Pins.BPM: "Bubbles per Minute",
52+
self.Pins.TEMPERATURE: "Temperature",
53+
self.Pins.BATCH_VOLUME: "Batch Volume",
54+
self.Pins.OG: "Original Gravity",
55+
self.Pins.SG: "Specific Gravity",
56+
self.Pins.ABV: "Alcohol by Volume",
57+
self.Pins.BUBBLES: "Bubbles",
58+
self.Pins.CO2_VOLUME: "CO2 Volume",
59+
}
60+
return names.get(pin, pin.name)
61+
62+
@property
63+
def sensors(self) -> dict:
64+
return {
65+
self.Pins.BPM: self.bmp,
66+
self.Pins.TEMPERATURE: self.temperature,
67+
self.Pins.BATCH_VOLUME: self.batch_volume,
68+
self.Pins.OG: self.og,
69+
self.Pins.SG: self.sg,
70+
self.Pins.ABV: self.abv,
71+
self.Pins.BUBBLES: self.bubbles,
72+
self.Pins.CO2_VOLUME: self.co2_volume,
73+
}
74+
75+
def get_unit_of_measurement(self, pin: PinsBase):
76+
if pin == self.Pins.TEMPERATURE:
77+
return self.temperature_unit
78+
if pin == self.Pins.BATCH_VOLUME or pin == self.Pins.CO2_VOLUME:
79+
return self.volume_unit
80+
if pin == self.Pins.BPM:
81+
return UNIT_BUBBLES_PER_MINUTE
82+
if pin == self.Pins.ABV:
83+
return UNIT_PERCENTAGE
84+
85+
return ""
86+
87+
# noinspection PyTypeChecker
88+
@staticmethod
89+
def pins():
90+
return list(PlaatoAirlock.Pins)
91+
92+
class Pins(PinsBase, Enum):
93+
BPM = "v102"
94+
TEMPERATURE = "v103"
95+
BATCH_VOLUME = "v104"
96+
OG = "v105"
97+
SG = "v106"
98+
ABV = "v107"
99+
TEMPERATURE_UNIT = "v108"
100+
VOLUME_UNIT = "v109"
101+
BUBBLES = "v110"
102+
CO2_VOLUME = "v119"

pyplaato/models/device.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from abc import abstractmethod, ABC
2+
from datetime import datetime
3+
from enum import Enum
4+
5+
from pyplaato.models.pins import PinsBase
6+
7+
8+
class PlaatoDeviceType(str, Enum):
9+
Airlock = "Airlock"
10+
Keg = "Keg"
11+
12+
13+
class PlaatoDevice(ABC):
14+
@property
15+
@abstractmethod
16+
def device_type(self) -> PlaatoDeviceType:
17+
pass
18+
19+
@property
20+
@abstractmethod
21+
def name(self) -> str:
22+
pass
23+
24+
@property
25+
def date(self) -> float:
26+
return datetime.now().timestamp()
27+
28+
@property
29+
def firmware_version(self) -> str:
30+
return ""
31+
32+
@property
33+
@abstractmethod
34+
def sensors(self) -> dict:
35+
"""Convenience method for Home Assistant"""
36+
pass
37+
38+
@property
39+
def binary_sensors(self) -> dict:
40+
"""Convenience method for Home Assistant"""
41+
return {}
42+
43+
@property
44+
def attributes(self) -> dict:
45+
"""Convenience method for Home Assistant"""
46+
return {}
47+
48+
@abstractmethod
49+
def get_sensor_name(self, pin: PinsBase) -> str:
50+
"""Convenience method for Home Assistant"""
51+
pass
52+
53+
@abstractmethod
54+
def get_unit_of_measurement(self, pin: PinsBase):
55+
"""Convenience method to get unit of measurement for Home Assistant"""
56+
pass
57+
58+
@staticmethod
59+
@abstractmethod
60+
def pins() -> list:
61+
pass

pyplaato/models/keg.py

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
from datetime import datetime
2+
from enum import Enum
3+
4+
import dateutil.parser
5+
6+
from .device import PlaatoDevice, PlaatoDeviceType
7+
from .pins import PinsBase
8+
from ..const import UNIT_TEMP_CELSIUS, UNIT_TEMP_FAHRENHEIT, UNIT_PERCENTAGE
9+
10+
11+
class PlaatoKeg(PlaatoDevice):
12+
"""Class for holding a Plaato Keg"""
13+
14+
device_type = PlaatoDeviceType.Keg
15+
16+
def __init__(self, attrs):
17+
self.beer_left_unit = attrs.get(self.Pins.BEER_LEFT_UNIT, None)
18+
self.volume_unit = attrs.get(self.Pins.VOLUME_UNIT, None)
19+
self.mass_unit = attrs.get(self.Pins.MASS_UNIT, None)
20+
self.measure_unit = attrs.get(self.Pins.MEASURE_UNIT, None)
21+
self.og = attrs.get(self.Pins.OG, None)
22+
self.fg = attrs.get(self.Pins.FG, None)
23+
self.__mode = attrs.get(self.Pins.MODE, None)
24+
self.__firmware_version = attrs.get(self.Pins.FIRMWARE_VERSION, None)
25+
self.__leak_detection = attrs.get(self.Pins.LEAK_DETECTION, None)
26+
self.__abv = attrs.get(self.Pins.ABV, None)
27+
self.__name = attrs.get(self.Pins.BEER_NAME, "Beer")
28+
self.__percent_beer_left = attrs.get(self.Pins.PERCENT_BEER_LEFT, None)
29+
self.__pouring = attrs.get(self.Pins.POURING, False)
30+
self.__beer_left = attrs.get(self.Pins.BEER_LEFT, None)
31+
self.__temperature = attrs.get(self.Pins.TEMPERATURE, None)
32+
self.__temperature_unit = attrs.get(self.Pins.TEMPERATURE_UNIT, None)
33+
self.__last_pour = attrs.get(self.Pins.LAST_POUR, None)
34+
self.__date = attrs.get(self.Pins.DATE, None)
35+
36+
def __repr__(self):
37+
return f"{self.__class__.__name__} -> " \
38+
f"Bear Left: {self.beer_left}, " \
39+
f"Temp: {self.temperature}, " \
40+
f"Pouring: {self.pouring}"
41+
42+
@property
43+
def date(self) -> float:
44+
if self.__date is not None:
45+
date = dateutil.parser.parse(self.__date)
46+
return datetime.timestamp(date)
47+
return super().date
48+
49+
@property
50+
def temperature(self):
51+
if self.__temperature is not None:
52+
return round(float(self.__temperature), 1)
53+
54+
@property
55+
def temperature_unit(self):
56+
if self.__temperature_unit is "1":
57+
return UNIT_TEMP_CELSIUS
58+
return UNIT_TEMP_FAHRENHEIT
59+
60+
@property
61+
def beer_left(self):
62+
if self.__beer_left is not None:
63+
return round(float(self.__beer_left), 2)
64+
65+
@property
66+
def percent_beer_left(self):
67+
if self.__percent_beer_left is not None:
68+
return round(self.__percent_beer_left, 2)
69+
70+
@property
71+
def last_pour(self):
72+
if self.__last_pour is not None:
73+
return round(float(self.__last_pour), 2)
74+
75+
@property
76+
def last_pour_unit(self):
77+
if self.measure_unit is "1":
78+
return self.mass_unit
79+
return self.volume_unit
80+
81+
@property
82+
def abv(self):
83+
if self.__abv is not None:
84+
return round(float(self.__abv), 2)
85+
86+
@property
87+
def pouring(self):
88+
"""
89+
0 = Not Pouring
90+
255 = Pouring
91+
:return: True if 255 = Pouring else False
92+
"""
93+
return self.__pouring is "255"
94+
95+
@property
96+
def leak_detection(self):
97+
"""
98+
1 = Leaking
99+
0 = Not Leaking
100+
:return: True if 1 = Leaking else False
101+
"""
102+
return self.__leak_detection is "1"
103+
104+
@property
105+
def mode(self):
106+
"""
107+
1 = Beer
108+
2 = Co2
109+
"""
110+
return "Beer" if self.__mode is "1" else "Co2"
111+
112+
@property
113+
def name(self) -> str:
114+
return self.__name
115+
116+
@property
117+
def firmware_version(self) -> str:
118+
return self.__firmware_version
119+
120+
def get_sensor_name(self, pin: PinsBase) -> str:
121+
names = {
122+
self.Pins.PERCENT_BEER_LEFT: "Percent Beer Left",
123+
self.Pins.POURING: "Pouring",
124+
self.Pins.BEER_LEFT: "Beer Left",
125+
self.Pins.TEMPERATURE: "Temperature",
126+
self.Pins.LAST_POUR: "Last Pour Amount",
127+
self.Pins.OG: "Original Gravity",
128+
self.Pins.FG: "Final Gravity",
129+
self.Pins.ABV: "Alcohol by Volume",
130+
self.Pins.LEAK_DETECTION: "Leaking",
131+
self.Pins.MODE: "Mode",
132+
self.Pins.DATE: "Keg Date",
133+
self.Pins.BEER_NAME: "Beer Name"
134+
}
135+
return names.get(pin, pin.name)
136+
137+
@property
138+
def sensors(self) -> dict:
139+
return {
140+
self.Pins.PERCENT_BEER_LEFT: self.percent_beer_left,
141+
self.Pins.BEER_LEFT: self.beer_left,
142+
self.Pins.TEMPERATURE: self.temperature,
143+
self.Pins.LAST_POUR: self.last_pour
144+
}
145+
146+
@property
147+
def binary_sensors(self) -> dict:
148+
return {
149+
self.Pins.LEAK_DETECTION: self.leak_detection,
150+
self.Pins.POURING: self.pouring,
151+
}
152+
153+
@property
154+
def attributes(self) -> dict:
155+
return {
156+
self.get_sensor_name(self.Pins.BEER_NAME): self.name,
157+
self.get_sensor_name(self.Pins.DATE): datetime.fromtimestamp(self.date).strftime('%x'),
158+
self.get_sensor_name(self.Pins.MODE): self.mode,
159+
self.get_sensor_name(self.Pins.OG): self.og,
160+
self.get_sensor_name(self.Pins.FG): self.fg,
161+
self.get_sensor_name(self.Pins.ABV): self.abv
162+
}
163+
164+
def get_unit_of_measurement(self, pin: PinsBase):
165+
if pin == self.Pins.BEER_LEFT:
166+
return self.beer_left_unit
167+
if pin == self.Pins.TEMPERATURE:
168+
return self.temperature_unit
169+
if pin == self.Pins.LAST_POUR:
170+
return self.last_pour_unit
171+
if pin == self.Pins.ABV or pin == self.Pins.PERCENT_BEER_LEFT:
172+
return UNIT_PERCENTAGE
173+
174+
return ""
175+
176+
# noinspection PyTypeChecker
177+
@staticmethod
178+
def pins():
179+
return list(PlaatoKeg.Pins)
180+
181+
class Pins(PinsBase, Enum):
182+
BEER_NAME = "v64"
183+
PERCENT_BEER_LEFT = "v48"
184+
POURING = "v49"
185+
BEER_LEFT = "v51"
186+
BEER_LEFT_UNIT = "v74"
187+
TEMPERATURE = "v56"
188+
TEMPERATURE_UNIT = "v71"
189+
MEASURE_UNIT = "v75"
190+
MASS_UNIT = "v73"
191+
VOLUME_UNIT = "v82"
192+
LAST_POUR = "v59"
193+
DATE = "v67"
194+
OG = "v65"
195+
FG = "v66"
196+
ABV = "v68"
197+
FIRMWARE_VERSION = "v93"
198+
LEAK_DETECTION = "v83"
199+
MODE = "v88"

pyplaato/models/pins.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from enum import Enum
2+
3+
4+
class PinsBase(str, Enum):
5+
"""Base class"""

0 commit comments

Comments
 (0)