import asyncio import logging from unittest.mock import MagicMock, patch from cbpi.api import * logger = logging.getLogger(__name__) try: import RPi.GPIO as GPIO except Exception: logger.warning("Failed to load RPi.GPIO. Using Mock instead") MockRPi = MagicMock() modules = { "RPi": MockRPi, "RPi.GPIO": MockRPi.GPIO } patcher = patch.dict("sys.modules", modules) patcher.start() import RPi.GPIO as GPIO mode = GPIO.getmode() if (mode == None): GPIO.setmode(GPIO.BCM) @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.Select(label="Inverted", options=["Yes", "No"],description="No: Active on high; Yes: Active on low"), Property.Select(label="SamplingTime", options=[2,5],description="Time in seconds for power base interval (Default:5)")]) class GPIOActor(CBPiActor): # Custom property which can be configured by the user @action("Set Power", parameters=[Property.Number(label="Power", configurable=True,description="Power Setting [0-100]")]) async def setpower(self,Power = 100 ,**kwargs): self.power=int(Power) if self.power < 0: self.power = 0 if self.power > 100: self.power = 100 await self.set_power(self.power) def get_GPIO_state(self, state): # ON if state == 1: return 1 if self.inverted == False else 0 # OFF if state == 0: return 0 if self.inverted == False else 1 async def on_start(self): self.power = None self.gpio = self.props.GPIO self.inverted = True if self.props.get("Inverted", "No") == "Yes" else False self.sampleTime = int(self.props.get("SamplingTime", 5)) GPIO.setup(self.gpio, GPIO.OUT) GPIO.output(self.gpio, self.get_GPIO_state(0)) self.state = False async def on(self, power = None): if power is not None: self.power = power else: self.power = 100 # await self.set_power(self.power) logger.info("ACTOR %s ON - GPIO %s " % (self.id, self.gpio)) GPIO.output(self.gpio, self.get_GPIO_state(1)) self.state = True async def off(self): logger.info("ACTOR %s OFF - GPIO %s " % (self.id, self.gpio)) GPIO.output(self.gpio, self.get_GPIO_state(0)) self.state = False def get_state(self): return self.state async def run(self): while self.running == True: if self.state == True: heating_time=self.sampleTime * (self.power / 100) wait_time=self.sampleTime - heating_time if heating_time > 0: #logging.info("Heating Time: {}".format(heating_time)) GPIO.output(self.gpio, self.get_GPIO_state(1)) await asyncio.sleep(heating_time) if wait_time > 0: #logging.info("Wait Time: {}".format(wait_time)) GPIO.output(self.gpio, self.get_GPIO_state(0)) await asyncio.sleep(wait_time) else: await asyncio.sleep(1) async def set_power(self, power): self.power = power await self.cbpi.actor.actor_update(self.id,power) 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), 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 @action("Set Power", parameters=[Property.Number(label="Power", configurable=True,description="Power Setting [0-100]")]) async def setpower(self,Power = 100 ,**kwargs): logging.info(Power) self.power=int(Power) if self.power < 0: self.power = 0 if self.power > 100: self.power = 100 await self.set_power(self.power) 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) if self.inverted == "No": GPIO.output(self.gpio, 0) else: GPIO.output(self.gpio, 1) self.state = False self.power = None self.p = None pass async def on(self, power = None): logging.debug("PWM Actor Power: {}".format(power)) if power is not None: self.power = power else: self.power = 100 logging.debug("PWM Final Power: {}".format(self.power)) logger.debug("PWM ACTOR %s ON - GPIO %s - Frequency %s - Power %s" % (self.id, self.gpio,self.frequency,self.power)) try: if self.p is None: self.p = GPIO.PWM(int(self.gpio), float(self.frequency)) 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: pass async def off(self): logger.info("PWM ACTOR %s OFF - GPIO %s " % (self.id, self.gpio)) 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: 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 def get_state(self): return self.state async def run(self): while self.running == True: await asyncio.sleep(1) def setup(cbpi): ''' This method is called by the server during startup Here you need to register your plugins at the server :param cbpi: the cbpi core :return: ''' cbpi.plugin.register("GPIOActor", GPIOActor) cbpi.plugin.register("GPIOPWMActor", GPIOPWMActor)