diff --git a/cbpi/__init__.py b/cbpi/__init__.py index 70a060f..92c0b96 100644 --- a/cbpi/__init__.py +++ b/cbpi/__init__.py @@ -1,3 +1,3 @@ -__version__ = "4.3.2" -__codename__ = "Winter Storm" +__version__ = "4.4.0" +__codename__ = "Yeast Starter" diff --git a/cbpi/controller/satellite_controller.py b/cbpi/controller/satellite_controller.py index 7b8e545..19f2dc5 100644 --- a/cbpi/controller/satellite_controller.py +++ b/cbpi/controller/satellite_controller.py @@ -53,7 +53,7 @@ class SatelliteController: except asyncio.CancelledError: pass - self.client = Client(self.host, port=self.port, username=self.username, password=self.password, will=Will(topic="cbpi/disconnect", payload="CBPi Server Disconnected"),client_id=self.client_id) + self.client = Client(self.host, port=self.port, username=self.username, password=self.password, will=Will(topic="cbpi/disconnect", payload="CBPi Server Disconnected"),identifier=self.client_id) self.loop = asyncio.get_event_loop() ## Listen for mqtt messages in an (unawaited) asyncio task task = self.loop.create_task(self.listen()) @@ -67,9 +67,8 @@ class SatelliteController: while True: try: async with self.client as client: - async with client.messages() as messages: await client.subscribe("#") - async for message in messages: + async for message in client.messages: for topic_filter in self.topic_filters: topic = topic_filter[0] method = topic_filter[1] @@ -158,30 +157,10 @@ class SatelliteController: except Exception as e: self.logger.warning("Failed to send sensorupdate via mqtt: {}".format(e)) - def subcribe(self, topic, method): - task = asyncio.create_task(self._subcribe(topic, method)) - return task - - async def _subcribe(self, topic, method): - self.error=False - while True: - try: - if self.client._connected.done(): - async with self.client.messages() as messages: - await self.client.subscribe(topic) - async for message in messages: - if message.topic.matches(topic): - await method(message.payload.decode()) - except asyncio.CancelledError: - # Cancel - self.logger.warning("Subscription {} Cancelled".format(topic)) - self.error=True - except MqttError as e: - self.logger.error("Sub MQTT Exception: {}".format(e)) - except Exception as e: - self.logger.error("Sub Exception: {}".format(e)) - # wait before try to resubscribe - if self.error == True: - break - else: - await asyncio.sleep(5) + def subscribe(self, topic, method): + self.topic_filters.append((topic,method)) + return True + + def unsubscribe(self, topic, method): + self.topic_filters.remove((topic,method)) + return True diff --git a/cbpi/craftbeerpi.py b/cbpi/craftbeerpi.py index c11295f..dd8a37a 100644 --- a/cbpi/craftbeerpi.py +++ b/cbpi/craftbeerpi.py @@ -263,7 +263,7 @@ class CraftBeerPi: f = Figlet(font='big') logger.warning("\n%s" % f.renderText("CraftBeerPi %s " % self.version)) logger.warning("www.CraftBeerPi.com") - logger.warning("(c) 2021/2022/2023 Manuel Fritsch / Alexander Vollkopf") + logger.warning("(c) 2021 - 2024 Manuel Fritsch / Alexander Vollkopf") def _setup_http_index(self): async def http_index(request): diff --git a/cbpi/extension/gpioactor/__init__.py b/cbpi/extension/gpioactor/__init__.py index 93141e9..eb16338 100644 --- a/cbpi/extension/gpioactor/__init__.py +++ b/cbpi/extension/gpioactor/__init__.py @@ -97,7 +97,9 @@ class GPIOActor(CBPiActor): pass -@parameters([Property.Select(label="GPIO", options=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]), Property.Number(label="Frequency", configurable=True)]) +@parameters([Property.Select(label="GPIO", options=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]), + Property.Number(label="Frequency", configurable=True), + Property.Select(label="Inverted",options=["Yes","No"],description="Inverts PWM load if set to yes (e.g. 90% = 10%). Default: No")]) class GPIOPWMActor(CBPiActor): # Custom property which can be configured by the user @@ -113,10 +115,14 @@ class GPIOPWMActor(CBPiActor): async def on_start(self): self.gpio = self.props.get("GPIO", None) + self.inverted = self.props.get("Inverted", "No") self.frequency = self.props.get("Frequency", 0.5) if self.gpio is not None: GPIO.setup(self.gpio, GPIO.OUT) - GPIO.output(self.gpio, 0) + if self.inverted == "No": + GPIO.output(self.gpio, 0) + else: + GPIO.output(self.gpio, 1) self.state = False self.power = None self.p = None @@ -135,7 +141,10 @@ class GPIOPWMActor(CBPiActor): try: if self.p is None: self.p = GPIO.PWM(int(self.gpio), float(self.frequency)) - self.p.start(self.power) + if self.inverted == "No": + self.p.start(self.power) + else: + self.p.start(100- self.power) self.state = True # await self.cbpi.actor.actor_update(self.id,self.power) except: @@ -143,12 +152,19 @@ class GPIOPWMActor(CBPiActor): async def off(self): logger.info("PWM ACTOR %s OFF - GPIO %s " % (self.id, self.gpio)) - self.p.ChangeDutyCycle(0) + if self.inverted == "No": + self.p.ChangeDutyCycle(0) + else: + self.p.ChangeDutyCycle(100) + self.state = False async def set_power(self, power): if self.p and self.state == True: - self.p.ChangeDutyCycle(power) + if self.inverted == "No": + self.p.ChangeDutyCycle(power) + else: + self.p.ChangeDutyCycle(100 - power) # Set power to 100-value to invert output await self.cbpi.actor.actor_update(self.id,power) pass diff --git a/cbpi/extension/mqtt_sensor/__init__.py b/cbpi/extension/mqtt_sensor/__init__.py index 47114cf..c5b0c0b 100644 --- a/cbpi/extension/mqtt_sensor/__init__.py +++ b/cbpi/extension/mqtt_sensor/__init__.py @@ -24,7 +24,7 @@ class MQTTSensor(CBPiSensor): self.payload_text = self.props.get("PayloadDictionary", None) if self.payload_text != None: self.payload_text = self.payload_text.split('.') - self.mqtt_task = self.cbpi.satellite.subcribe(self.Topic, self.on_message) + self.subscribed = self.cbpi.satellite.subscribe(self.Topic, self.on_message) self.value: float = 999 self.timeout=int(self.props.get("Timeout", 60)) self.starttime = time.time() @@ -55,7 +55,7 @@ class MQTTSensor(CBPiSensor): pass async def on_message(self, message): - val = json.loads(message) + val = json.loads(message.payload.decode()) try: if self.payload_text is not None: for key in self.payload_text: @@ -130,17 +130,8 @@ class MQTTSensor(CBPiSensor): return dict(value=self.value) async def on_stop(self): - was_cancelled=False - if not self.mqtt_task.done(): - logging.info("Task not done -> cancelling") - was_cancelled = self.mqtt_task.cancel() - try: - logging.info("Trying to call cancelled task") - await self.mqtt_task - except asyncio.CancelledError: - logging.info("Task has been Cancelled") - pass - logging.info("Task cancelled: {}".format(was_cancelled)) + self.subscribed = self.cbpi.satellite.unsubscribe(self.Topic, self.on_message) + def setup(cbpi): ''' diff --git a/requirements.txt b/requirements.txt index 09cd3d4..96370cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ typing-extensions>=4 -aiohttp==3.9.3 +aiohttp==3.9.4 aiohttp-auth==0.1.1 aiohttp-route-decorator==0.1.4 aiohttp-security==0.5.0 @@ -8,22 +8,22 @@ aiohttp-swagger==1.0.16 async-timeout==4.0.3 aiojobs==1.2.1 aiosqlite==0.17.0 -cryptography==41.0.7 -pyopenssl==23.3.0 +cryptography==42.0.5 +pyopenssl==24.1.0 requests==2.31.0 -voluptuous==0.13.1 +voluptuous==0.14.2 pyfiglet==1.0.2 -pandas==1.5.3 -shortuuid==1.0.11 +pandas==2.2.2 +shortuuid==1.0.13 tabulate==0.9.0 -numpy==1.24.1 +numpy==1.26.4 cbpi4gui click==8.1.7 importlib_metadata==4.11.1 -aiomqtt==1.2.1 -psutil==5.9.6 +aiomqtt==2.0.1 +psutil==5.9.8 zipp>=0.5 colorama==0.4.6 pytest-aiohttp coverage==6.3.1 -inquirer==3.1.3 +inquirer==3.2.4 diff --git a/setup.py b/setup.py index 8def85b..fab42ac 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ setup(name='cbpi4', long_description_content_type='text/markdown', install_requires=[ "typing-extensions>=4", - "aiohttp==3.9.3", + "aiohttp==3.9.4", "aiohttp-auth==0.1.1", "aiohttp-route-decorator==0.1.4", "aiohttp-security==0.5.0", @@ -48,22 +48,22 @@ setup(name='cbpi4', "async-timeout==4.0.3", "aiojobs==1.2.1 ", "aiosqlite==0.17.0", - "cryptography==41.0.7", - "pyopenssl==23.3.0", + "cryptography==42.0.5", + "pyopenssl==24.1.0", "requests==2.31.0", - "voluptuous==0.13.1", + "voluptuous==0.14.2", "pyfiglet==1.0.2", 'click==8.1.7', - 'shortuuid==1.0.11', + 'shortuuid==1.0.13', 'tabulate==0.9.0', - 'aiomqtt==1.2.1', - 'inquirer==3.1.3', + 'aiomqtt==2.0.1', + 'inquirer==3.2.4', 'colorama==0.4.6', - 'psutil==5.9.6', + 'psutil==5.9.8', 'cbpi4gui', 'importlib_metadata', - 'numpy==1.24.1', - 'pandas==1.5.3'] + ( + 'numpy==1.26.4', + 'pandas==2.2.2'] + ( ['rpi-lgpio'] if raspberrypi else [] ), dependency_links=[