Exemplo n.º 1
0
class Todo:
    def __init__(self):
        self.mqtt = Mqtt()
        self.mqtt.set_on_message(self._on_message)

    def _on_message(self, mqtt, topic, msg):
        if msg == b'on':
            import wakeup
            wakeup.send()
        elif msg == b'off':
            pass
        else:
            pass

        gc.collect()

    def run(self):
        self.mqtt.start()
Exemplo n.º 2
0
fanout_thread.start()

ctl_thread = ControlThread(logic_board_out, raw_bypass_queue,
                           cmd_to_control_queue)
ctl_thread.start()

if 'link' in cfg and cfg['link']['url']:
    linker_thread = Linker(cfg['link']['url'], cmd_to_linker_queue)
    linker_thread.start()

if 'mqtt' in cfg and cfg['mqtt']['url']:
    mqtt_thread = Mqtt(cfg['mqtt']['url'], cfg['mqtt']['port'],
                       cfg['mqtt']['use_ssl'], cfg['mqtt']['validate_cert'],
                       cfg['mqtt']['user'], cfg['mqtt']['passwd'],
                       cmd_to_mqtt_queue, cmd_queue)
    mqtt_thread.start()

panel_status_thread = PanelStatus(panel_in, cmd_queue, raw_bypass_queue)
panel_status_thread.start()

cron_thread = CronCommands(cmd_queue)
cron_thread.start()

sleep_thread = SleepThread(cmd_queue)
sleep_thread.start()

# webservice / flask
app = Flask("SeviControl")
app.logger.setLevel(logging.DEBUG)
CORS(app)
Exemplo n.º 3
0
class Irrigate:
    def __init__(self, configFilename):
        self.startTime = datetime.now()
        self.logger = self.getLogger()
        self.logger.info("Reading configuration file '%s'..." % configFilename)
        self.init(configFilename)
        self.terminated = False
        self.mqtt = Mqtt(self)
        self.createThreads()
        self._intervalDict = {}
        self.sensors = {}

    def start(self, test=True):
        if self.cfg.mqttEnabled:
            self.logger.info("Starting MQTT...")
            self.mqtt.start()

        self.logger.debug("Starting worker threads...")
        for worker in self.workers:
            self.logger.info("Starting worker thread '%s'." % worker.getName())
            worker.setDaemon(test)
            worker.start()

        self.logger.debug("Starting sensors...")
        for sch in self.cfg.schedules.values():
            if sch.sensor != None:
                sensorHandler = sch.sensor.handler
                try:
                    if not sensorHandler.started:
                        self.logger.info("Starting sensor '%s'." %
                                         format(sensorHandler))
                        sensorHandler.start()
                        self.sensors[sch.sensor.type] = sensorHandler
                except Exception as ex:
                    self.logger.error("Error starting sensor '%s': '%s'." %
                                      (sch.sensor.type, format(ex)))

        self.logger.info("Starting timer thread '%s'." % self.timer.getName())
        self.timer.start()

    def init(self, cfgFilename):
        self.cfg = config.Config(self.logger, cfgFilename)
        self.valves = self.cfg.valves
        self.q = queue.Queue()

    def createThreads(self):
        self.workers = []
        for i in range(self.cfg.valvesConcurrency):
            worker = Thread(target=self.valveThread, args=())
            worker.setDaemon(False)
            worker.setName("ValveTh%s" % i)
            self.workers.append(worker)

        self.timer = Thread(target=self.timerThread, args=())
        self.timer.setDaemon(True)
        self.timer.setName("TimerTh")

    def evalSched(self, sched, timezone, now):
        todayStr = calendar.day_abbr[datetime.today().weekday()]
        if not todayStr in sched.days:
            return False

        lat, lon = self.cfg.getLatLon()
        if sched.seasons != None and not self.getSeason(lat) in sched.seasons:
            return False

        hours, minutes = sched.start.split(":")
        startTime = datetime.now()

        if sched.type == 'absolute':
            startTime = startTime.replace(hour=int(hours),
                                          minute=int(minutes),
                                          second=0,
                                          microsecond=0,
                                          tzinfo=pytz.timezone(timezone))
        else:
            sun = Sun(lat, lon)
            if sched.type == 'sunrise':
                startTime = sun.get_local_sunrise_time().replace(
                    second=0, microsecond=0, tzinfo=pytz.timezone(timezone))
            elif sched.type == 'sunset':
                startTime = sun.get_local_sunset_time().replace(
                    second=0, microsecond=0, tzinfo=pytz.timezone(timezone))

        if hours[0] == '+':
            hours = hours[1:]
            startTime = startTime + timedelta(hours=int(hours),
                                              minutes=int(minutes))
        if hours[0] == '-':
            hours = hours[1:]
            startTime = startTime - timedelta(hours=int(hours),
                                              minutes=int(minutes))

        if startTime == now:
            return True

        return False

    def getSeason(self, lat):
        month = datetime.today().month
        season = None
        if lat >= 0:
            if 3 <= month <= 5:
                season = "Spring"
            elif 6 <= month <= 8:
                season = "Summer"
            elif 9 <= month <= 11:
                season = "Fall"
            elif month == 12 or month <= 2:
                season = "Winter"
        else:
            if 3 <= month <= 5:
                season = "Fall"
            elif 6 <= month <= 8:
                season = "Winter"
            elif 9 <= month <= 11:
                season = "Spring"
            elif month == 12 or month <= 2:
                season = "Summer"

        return season

    def valveThread(self):
        while not self.terminated:
            try:
                irrigateJob = self.q.get(timeout=5)
                if irrigateJob.valve.handled:
                    self.logger.warning(
                        "Valve '%s' already handled. Returning to queue in 1 minute."
                        % (irrigateJob.valve.name))
                    time.sleep(61)
                    self.q.put(irrigateJob)
                else:
                    valve = irrigateJob.valve
                    valve.handled = True
                    self.logger.info(
                        "Irrigation cycle start for valve '%s' for %s minutes."
                        % (valve.name, irrigateJob.duration))
                    duration = timedelta(minutes=irrigateJob.duration)
                    valve.secondsLast = 0
                    valve.secondsRemain = duration.seconds
                    initialOpen = valve.secondsDaily
                    sensorDisabled = False
                    openSince = None
                    startTime = datetime.now()
                    while startTime + duration > datetime.now():
                        # The following two if statements needs to be together and first to prevent
                        # the valve from opening if the sensor is disable.
                        if irrigateJob.sensor != None and irrigateJob.sensor.handler.started:
                            try:
                                holdSensorDisabled = irrigateJob.sensor.handler.shouldDisable(
                                )
                                if holdSensorDisabled != sensorDisabled:
                                    sensorDisabled = holdSensorDisabled
                                    self.logger.info(
                                        "Suspend set to '%s' for valve '%s' from sensor"
                                        % (sensorDisabled, valve.name))
                            except Exception as ex:
                                self.logger.error(
                                    "Error probing sensor (shouldDisable) '%s': %s."
                                    % (irrigateJob.sensor.type, format(ex)))
                        if not valve.open and not valve.suspended and not sensorDisabled:
                            valve.open = True
                            openSince = datetime.now()
                            valve.handler.open()
                            self.logger.info("Irrigation valve '%s' opened." %
                                             (valve.name))

                        if valve.open and (valve.suspended or sensorDisabled):
                            valve.open = False
                            valve.secondsLast = (datetime.now() -
                                                 openSince).seconds
                            openSince = None
                            valve.secondsDaily = initialOpen + valve.secondsLast
                            initialOpen = valve.secondsDaily
                            valve.secondsLast = 0
                            valve.handler.close()
                            self.logger.info("Irrigation valve '%s' closed." %
                                             (valve.name))
                        if valve.open:
                            valve.secondsLast = (datetime.now() -
                                                 openSince).seconds
                            valve.secondsDaily = initialOpen + valve.secondsLast
                        if valve.enabled == False:
                            self.logger.info(
                                "Valve '%s' disabled. Terminating irrigation cycle."
                                % (valve.name))
                            break
                        if self.terminated:
                            self.logger.warning(
                                "Program exiting. Terminating irrigation cycle for valve '%s'..."
                                % (valve.name))
                            break

                        valve.secondsRemain = ((startTime + duration) -
                                               datetime.now()).seconds
                        self.logger.debug("Irrigation valve '%s' Last Open = %ss. Remaining = %ss. Daily Total = %ss." \
                          % (valve.name, valve.secondsLast, valve.secondsRemain, valve.secondsDaily))
                        time.sleep(1)

                    self.logger.info("Irrigation cycle ended for valve '%s'." %
                                     (valve.name))
                    if valve.open and not valve.suspended:
                        valve.secondsLast = (datetime.now() -
                                             openSince).seconds
                        valve.secondsDaily = initialOpen + valve.secondsLast
                    if valve.open:
                        valve.open = False
                        valve.handler.close()
                        self.logger.info(
                            "Irrigation valve '%s' closed. Overall open time %s seconds."
                            % (valve.name, valve.secondsDaily))
                    valve.handled = False
                self.q.task_done()
            except queue.Empty:
                pass
        self.logger.warning("Valve handler thread '%s' exited." %
                            threading.currentThread().getName())

    def queueJob(self, job):
        self.q.put(job)
        if job.sched != None:
            self.logger.info(
                "Valve '%s' job queued per sched '%s'. Duration %s minutes." %
                (job.valve.name, job.sched.name, job.duration))
        else:
            self.logger.info(
                "Valve '%s' adhoc job queued. Duration %s minutes." %
                (job.valve.name, job.duration))

    def everyXMinutes(self, key, interval, bootstrap):
        if not key in self._intervalDict.keys():
            self._intervalDict[key] = datetime.now()
            return bootstrap

        if datetime.now() >= self._intervalDict[key] + timedelta(
                minutes=interval):
            self._intervalDict[key] = datetime.now()
            return True

        return False

    def timerThread(self):
        try:
            while True:
                now = datetime.now().replace(tzinfo=pytz.timezone(
                    self.cfg.timezone),
                                             second=0,
                                             microsecond=0)

                if now.hour == 0 and now.minute == 0:
                    for aValve in self.valves.values():
                        aValve.secondsDaily = 0

                if self.everyXMinutes("idleInterval",
                                      self.cfg.telemIdleInterval,
                                      False) and self.cfg.telemetry:
                    delta = (datetime.now() - self.startTime)
                    uptime = ((delta.days * 86400) + delta.seconds) // 60
                    self.mqtt.publish("/svc/uptime", uptime)
                    for valve in self.valves.values():
                        self.telemetryValve(valve)

                    for sensor in self.sensors.keys():
                        self.telemetrySensor(sensor, self.sensors[sensor])

                if self.everyXMinutes("activeinterval",
                                      self.cfg.telemActiveInterval,
                                      False) and self.cfg.telemetry:
                    for valve in self.valves.values():
                        if valve.handled:
                            self.telemetryValve(valve)

                if self.everyXMinutes("scheduler", 1, True):
                    # Must not evaluate more or less than once every minute otherwise running jobs will get queued again
                    for aValve in self.valves.values():
                        if aValve.enabled:
                            if aValve.schedules != None:
                                for valveSched in aValve.schedules.values():
                                    if self.evalSched(valveSched,
                                                      self.cfg.timezone, now):
                                        jobDuration = valveSched.duration
                                        if valveSched.sensor != None and valveSched.sensor.handler != None and valveSched.sensor.handler.started:
                                            try:
                                                factor = valveSched.sensor.handler.getFactor(
                                                )
                                                if factor != 1:
                                                    jobDuration = jobDuration * factor
                                                    self.logger.info(
                                                        "Job duration changed from '%s' to '%s' based on input from sensor."
                                                        % (valveSched.duration,
                                                           jobDuration))
                                            except Exception as ex:
                                                self.logger.error(
                                                    "Error probing sensor (getFactor) '%s': %s."
                                                    % (valveSched.sensor.type,
                                                       format(ex)))
                                        job = model.Job(
                                            valve=aValve,
                                            duration=jobDuration,
                                            sched=valveSched,
                                            sensor=valveSched.sensor)
                                        self.queueJob(job)

                time.sleep(1)
        except Exception as ex:
            self.logger.error(
                "Timer thread exited with error '%s'. Terminating Irrigate!" %
                format(ex))
            self.terminated = True

    def telemetryValve(self, valve):
        statusStr = "enabled"
        if not valve.enabled:
            statusStr = "disabled"
        elif valve.suspended:
            statusStr = "suspended"
        elif valve.open:
            statusStr = "open"
        self.mqtt.publish(valve.name + "/status", statusStr)
        self.mqtt.publish(valve.name + "/dailytotal", valve.secondsDaily)
        self.mqtt.publish(valve.name + "/remaining", valve.secondsRemain)
        if valve.open:
            self.mqtt.publish(valve.name + "/secondsLast", valve.secondsLast)

    def telemetrySensor(self, name, sensor):
        prefix = "sensor/" + name + "/"
        statusStr = "Enabled"
        try:
            if sensor.shouldDisable():
                statusStr = "Disabled"
            elif sensor.getFactor() != 1:
                statusStr = "Factored"
            self.mqtt.publish(prefix + "factor", sensor.getFactor())
            telem = sensor.getTelemetry()
            if telem != None:
                for t in telem.keys():
                    self.mqtt.publish(prefix + t, telem[t])
        except Exception as ex:
            statusStr = "Error"
        self.mqtt.publish(prefix + "status", statusStr)

    def getLogger(self):
        formatter = logging.Formatter(
            fmt='%(asctime)s %(levelname)-8s %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S')
        handler = logging.FileHandler('log.txt', mode='w')
        handler.setFormatter(formatter)
        screen_handler = logging.StreamHandler(stream=sys.stdout)
        # screen_handler.setFormatter(formatter)
        logger = logging.getLogger("MyLogger")
        logger.setLevel(logging.DEBUG)
        logger.addHandler(handler)
        logger.addHandler(screen_handler)
        return logger
Exemplo n.º 4
0
        'location': style[0]
    })


def publish_status(status_manager):
    print("publish status", status_manager.status)
    mqtt.simple_send("doors/status", status_manager.status, retain=True)
    mqtt.simple_send("status/doorserver/public",
                     status_manager.public,
                     retain=True)
    mqtt.simple_send("status/doorserver/locked",
                     not status_manager.open,
                     retain=True)
    mqtt.simple_send("status/doorserver/occupied",
                     status_manager.occupied,
                     retain=True)


hmac_calculator = hmac.new(config.hmac_key, digestmod='sha512')
validator = Validator(hmac_calculator)
status = StatusManager(on_change=publish_status)
interpreter = Interpreter(status_manager=status,
                          open_door=open_door,
                          close_door=close_door,
                          alarm_door=alarm_door)
mqtt = Mqtt(addr=config.mqtt_broker,
            validator=validator,
            interpreter=interpreter,
            status_manager=status)
mqtt.start()