Beispiel #1
0
class DoorMonitorApp(MDApp):
    """
    Frontend for CatchScanner configuration

    """
    connection = ObjectProperty()
    current_user = StringProperty()
    access_level = NumericProperty(0)
    access = ObjectProperty(None)
    gui = ObjectProperty()
    api_response = ObjectProperty()

    timer_cnt = BoundedNumericProperty(5, min=0, max=ACCESS_TIMEOUT)
    timer = None
    _mqttc = mqtt.Client

    def __init__(self, cfg: dict) -> None:
        super().__init__()

        bell_config = MqttStringConfig(**cfg['bell'])

        door_list = []
        for door, d_cfg in cfg['doors'].items():
            print(f"new_door: {door}")
            new_door = Door(door_id=door,
                            name=d_cfg['name'],
                            command_topic=d_cfg['command_topic'],
                            state_topic=d_cfg['state_topic'])
            # new_door.set_relay()
            door_list.append(new_door)

        doors_config = DoorsConfig(doors=door_list)

        print(cfg['garage'])

        garage_config = MqttStringConfig(**cfg['garage'])

        mode_config = MqttStringConfig(**cfg['mode'])

        self.kelvin = kelvin_rgb_to_kivy()
        self.azure = get_color_from_hex('#f0ffff')

        self.theme_cls = ThemeManager()
        self.theme_cls.primary_palette = "Blue"
        self.theme_cls.primary_hue = "500"
        self.theme_cls.accent_palette = "Yellow"
        self.theme_cls.accent_palette_hue = "500"
        self.theme_cls.theme_style = "Light"

        self.doors_config = doors_config
        self.bell_config = bell_config
        self.garage_config = garage_config
        self.mode_config = mode_config

        self.backlight = Backlight()

        ## GUI ##
        self.gui = ScreenManager(transition=NoTransition())
        try:
            self.screens = config.screens
        except AttributeError:
            self.screens = None
        else:
            for screen in self.screens:
                print(f'New screen: {screen}')
                try:
                    import_statemet = self.screens[screen][
                        "import"] + ' as NewScreen'
                    print(import_statemet)
                    exec(import_statemet)
                except Exception as e:
                    print(e)
                else:
                    screen_kwargs = {}
                    screen_kwargs.update({'name': screen})
                    # screen_kwargs.update({'controller':self})
                    # screen_kwargs.update({'sub':self.screens[screen].get("sub", None)})
                    # screen_kwargs.update({'memory':kwargs.get(screen,None)})

                    print(f'SCREEN NAME IS: {screen}')
                    print(f'with kwargs: {screen_kwargs}')

                    self.screens[screen]["object"] = eval('NewScreen')(
                        **screen_kwargs)

                    self.gui.add_widget(self.screens[screen]["object"])

        self.change_screen(self.gui.screen_names[0])

    def presence_out_of_bounds(self, am: AccessModel):
        print(f"USER OUT OF BOUNDS {am}")

    def presence_detected(self, am: AccessModel):
        print(f"presence_detected {am}")
        if am.name:
            self.current_user = am.name
            toast(f"Velkommen {am.name}")
        if am.access_level > 0:
            self.access_level = am.access_level
            self.change_screen('Control')
            self.screens['DoorBell']["object"].login_feedback(True)

    # def detected_beacon_response(self, request, result):
    #     if result is not None:
    #         try:
    #             self.access_level = result
    #             if self.access_level > 0:
    #                 self.change_screen('Control')
    #                 self.screens['DoorBell']["object"].login_feedback(True)
    #             else:
    #                 print("Login failed")
    #                 self.screens['DoorBell']["object"].login_feedback(False)
    #         except ValueError as e:
    #             print(f"result: {result}")
    #             print(e)
    #     else:
    #         print(f"result: {result}")

    # # def detected_beacon(self, devices_discovered, address, packet_type):
    # #         print(f'found: {devices_discovered} with address {address} aand packet type {packet_type}')

    # def detected_beacon(self, uuid, rssi):
    #     print(f'found uuid: {uuid} with rssi {rssi}')
    #     detected_beacon(on_success=self.detected_beacon_response,uuid=uuid, rssi=rssi)

    def get_door_name(self, door_id, *args):
        print(door_id)
        door = self.doors_config.get_by_id(door_id)
        if door is not None:
            return door.name
        else:
            return ""

    # @property
    # def access_level(self):
    #     print(f"current access level: {self.access_level}")
    #     return self.access_level

    def on_door_states(self, *args):
        print("on_door_states")

    def on_start(self):
        self.make_client()

    # def try_pin(self, pin):
    #     """"
    #     Log in.

    #     Log in to sw with user and password. Hardcoded for now. Should interact with DB.

    #     Args:
    #         user:       Username
    #         password:   Password

    #     """
    #     success = False
    #     success = self.api.authenticate_pin(pin)

    def next_screen(self):
        self.gui.next_screen()

    def prev_screen(self):
        self.gui.prev_screen()

    def on_enter_view(self, *args):
        pass

    def build(self):
        """
        Kivy build.

        Function to return Kivy Layout from App class.


        Returns:
            Widget containing GUI

        """
        return self.gui

    def try_login_response(self, request, result):
        self.access_level = result
        if result > 0:
            self.change_screen('Control')
            self.screens['DoorBell']["object"].login_feedback(True)
        else:
            print("Login failed")
            self.screens['DoorBell']["object"].login_feedback(False)

    def log_out(self, *args):
        self.access_level = 0
        self.change_screen("DoorBell")
        print(f"Log out, access level is: {self.access_level}")

    # def setaccess_level(self, level):
    #     self.access_level = level
    #     print(f"access level is: {self.access_level}")

    def start_log_out_timer(self):
        if self.access_level > 0:
            print(f"access timeout set")
            # self.acccess_timeout = Clock.schedule_once(self.acccess_timeout, ACCESS_TIMEOUT)
            self.timer_cnt = ACCESS_TIMEOUT
            self.timer = Clock.schedule_interval(self.tic, 1)

    def cancel_log_out_timer(self):
        self.timer.cancel()

    def tic(self, dt):
        self.timer_cnt -= 1

    def on_timer_cnt(self, *args):
        if self.timer_cnt == 0:
            self.cancel_log_out_timer()
            self.log_out()

    def extend_log_out_timer(self):
        self.timer_cnt = ACCESS_TIMEOUT

    # def acccess_timeout(self, dt):
    #     self.log_out()
    #     print(f"access level timeout")
    #     self.acccess_timeout.cancel()

    def try_login(self, pin, *args):
        try_login(pin=pin, on_success=self.try_login_response)

    #### MQTT STUFF ####
    def make_client(self):
        # parameters = {'self': self}
        self._mqttc = mqtt.Client(MQTT_CLIENT_ID)
        # self._mqttc = mqtt.Client(MQTT_CLIENT_ID, userdata = parameters)
        self._mqttc.on_message = self.mqtt_on_message
        self._mqttc.on_connect = self.mqtt_on_connect
        self._mqttc.on_publish = self.mqtt_on_publish
        self._mqttc.on_subscribe = self.mqtt_on_subscribe
        self.mqttc_connect_to_broker()
        self.mqttc_subscribe()
        self.mqttc_run()

    def mqtt_on_connect(self, mqttc, obj, flags, rc):
        print("rc: " + str(rc))
        print(f"flag: {flags}")

    def mqtt_on_message(self, mqttc, obj, msg):
        print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
        topic = msg.topic
        payload = msg.payload.decode("utf-8")

        door = self.doors_config.get_by_state_topic(topic)
        if door is not None:
            print(f"state received")
            if payload == DOORLOCK_STATUS_PAYLOAD.LOCKED:
                door.state = "LOCKED"
                self.screens['Control']["object"].update_door_states(
                    door.door_id, True)

            elif payload == DOORLOCK_STATUS_PAYLOAD.UNLOCKED:
                door.state = "UNLOCKED"
                self.screens['Control']["object"].update_door_states(
                    door.door_id, False)

        elif topic == self.mode_config.command_topic:
            print(f"mode received: {payload}")
            self.mode_config.state = payload

    def mqtt_on_publish(self, mqttc, obj, mid):
        print("mid: " + str(mid))

    def mqtt_on_subscribe(self, mqttc, obj, mid, granted_qos):
        print("Subscribed: " + str(mid) + " " + str(granted_qos))

    def mqtt_on_log(self, mqttc, obj, level, string):
        print(string)

    def tls_set(self):
        #TODO: sett ssl and cert for encrypt
        pass

    def mqttc_connect_to_broker(self):
        print(f"connecting to broker {MQTT_BROKER} as {MQTT_CLIENT_ID}")
        # broker_parsed = urllib.parse.urlparse(MQTT_BROKER)
        self._mqttc.username_pw_set(MQTT_USERNAME, password=MQTT_PASSWORD)
        self._mqttc.connect(MQTT_BROKER, port=MQTT_PORT, keepalive=60)

    def mqttc_subscribe(self):
        for door in self.doors_config.doors:
            self._mqttc.subscribe(door.state_topic, qos=0)
        self._mqttc.subscribe(self.mode_config.command_topic, qos=0)

    def mqttc_run(self):
        self._mqttc.loop_start()

    def ring_bell(self):
        print('ringing that bell')
        print(f'self.mode_config.state: {self.mode_config.state}')
        self._mqttc.publish(self.bell_config.command_topic,
                            payload=BELL_COMMAND_PAYLOAD.DO)
        if self.mode_config.state == MODE_COMMAND_PAYLOAD.NORMAL:
            pass
        elif self.mode_config.state == MODE_COMMAND_PAYLOAD.HALLOWEEN:
            self.change_screen('Scary')

    def toggle_door(self, door, locked, *args):
        if locked:

            for d in self.doors_config.doors:
                if d.name == door:
                    print(f"mqtt unlock door {door}")
                    self._mqttc.publish(
                        d.command_topic,
                        payload=DOORLOCK_COMMAND_PAYLOAD.UNLOCK)
        else:
            for d in self.doors_config.doors:
                if d.name == door:
                    print(f"mqtt lock door {door}")
                    self._mqttc.publish(d.command_topic,
                                        payload=DOORLOCK_COMMAND_PAYLOAD.LOCK)

    def garage_open(self, *args):
        self._mqttc.publish(self.garage_config.command_topic,
                            payload=GARAGE_COMMAND_PAYLOAD.OPEN)

    def garage_close(self, *args):
        self._mqttc.publish(self.garage_config.command_topic,
                            payload=GARAGE_COMMAND_PAYLOAD.CLOSE)

    def garage_stop(self, *args):
        self._mqttc.publish(self.garage_config.command_topic,
                            payload=GARAGE_COMMAND_PAYLOAD.STOP)

    def next_screen(self):
        self.change_screen(self.gui.next())

    def prev_screen(self):
        self.change_screen(self.gui.previous())

    def change_screen(self, screen_name):

        print(f"entering screen {screen_name}")

        # if screen_name == self.ids['sm'].screen_names[0]:
        #     print(f"screen is first")
        #     self.ids['sm'].current_screen.content.is_first()

        # else:
        #     print(f"screen is inbetween")
        #     # self.ids['sm'].current_screen.content.override_allow_prev(True)

        # if screen_name == self.ids['sm'].screen_names[-1]:
        #     print(f"screen is last")
        #     self.ids['sm'].current_screen.content.is_last()

        self.gui.current = screen_name