# Module `lib.server.presencecore`

Presence detection (determine if an occupant is present in the house)

Expand source code

    # Distributed under Pycameresp License
    # Copyright (c) 2023 Remi BERTHOLET
    # pylint:disable=consider-using-f-string
    """ Presence detection (determine if an occupant is present in the house) """
    import time
    import wifi.wifi
    import server.ping
    import server.notifier
    import tools.lang
    import tools.topic

    class PresenceCore:
            """ Presence detection of smartphones """
            ABSENCE_TIMEOUT   = 907
            NO_ANSWER_TIMEOUT = 421
            DNS_POLLING       = 67

            PING_TIMEOUT      = 0.5
            PING_COUNT        = 4

            detected = [False]
            last_time = 0
            last_dns_time = 0

            @staticmethod
            def set_detection(state):
                    """ Force presence detection """
                    PresenceCore.detected[0] = state

            @staticmethod
            def is_detected():
                    """ Indicates if presence detected """
                    return PresenceCore.detected[0]

            @staticmethod
            async def detect(presence_config, webhook_config):
                    """ Detect the presence or not of smartphones """
                    if PresenceCore.last_dns_time + PresenceCore.DNS_POLLING < time.time():
                            PresenceCore.last_dns_time = time.time()
                            sent,received,success = await server.ping.async_ping(wifi.wifi.Wifi.get_dns(), count=PresenceCore.PING_COUNT, timeout=PresenceCore.PING_TIMEOUT, quiet=True)

                            if received == 0:
                                    wifi.wifi.Wifi.lan_disconnected()
                            else:
                                    wifi.wifi.Wifi.lan_connected()

                    presents = []
                    current_detected = None
                    smartphone_in_list = False

                    for smartphone in presence_config.smartphones:
                            # If smartphone present
                            if smartphone != b"":
                                    smartphone_in_list = True

                                    # Ping smartphone
                                    sent,received,success = await server.ping.async_ping(smartphone, count=PresenceCore.PING_COUNT, timeout=PresenceCore.PING_TIMEOUT, quiet=True)

                                    # If a response received from smartphone
                                    if received > 0:
                                            presents.append(smartphone)
                                            PresenceCore.last_time = time.time()
                                            current_detected = True
                                            wifi.wifi.Wifi.lan_connected()

                    # If no smartphones detected during a very long time
                    if PresenceCore.last_time + PresenceCore.ABSENCE_TIMEOUT < time.time():
                            # Nobody in the house
                            current_detected = False

                    # If smartphone detected
                    if current_detected is True:
                            # If no smartphone previously detected
                            if PresenceCore.is_detected() != current_detected:
                                    # Notify the house is not empty
                                    msg = b""
                                    for present in presents:
                                            msg += b"%s "%present
                                    server.notifier.Notifier.notify(topic=tools.topic.presence_detected, value=tools.topic.value_on,  message=tools.lang.presence_of_s%(msg), enabled=presence_config.notify,url=webhook_config.inhabited_house)
                                    PresenceCore.set_detection(True)
                    # If no smartphone detected
                    elif current_detected is False:
                            # If smartphone previously detected
                            if PresenceCore.is_detected() != current_detected:
                                    # Notify the house in empty
                                    server.notifier.Notifier.notify(topic=tools.topic.presence_detected, value=tools.topic.value_off, message=tools.lang.empty_house, enabled=presence_config.notify,url=webhook_config.empty_house)
                                    PresenceCore.set_detection(False)

                    # If all smartphones not responded during a long time
                    if PresenceCore.last_time + PresenceCore.NO_ANSWER_TIMEOUT < time.time() and smartphone_in_list is True:
                            # Set fast polling rate
                            result = False
                    else:
                            # Reduce polling rate
                            result = True
                    return result

## Classes

`class PresenceCore`

  Presence detection of smartphones

  Expand source code

      class PresenceCore:
              """ Presence detection of smartphones """
              ABSENCE_TIMEOUT   = 907
              NO_ANSWER_TIMEOUT = 421
              DNS_POLLING       = 67

              PING_TIMEOUT      = 0.5
              PING_COUNT        = 4

              detected = [False]
              last_time = 0
              last_dns_time = 0

              @staticmethod
              def set_detection(state):
                      """ Force presence detection """
                      PresenceCore.detected[0] = state

              @staticmethod
              def is_detected():
                      """ Indicates if presence detected """
                      return PresenceCore.detected[0]

              @staticmethod
              async def detect(presence_config, webhook_config):
                      """ Detect the presence or not of smartphones """
                      if PresenceCore.last_dns_time + PresenceCore.DNS_POLLING < time.time():
                              PresenceCore.last_dns_time = time.time()
                              sent,received,success = await server.ping.async_ping(wifi.wifi.Wifi.get_dns(), count=PresenceCore.PING_COUNT, timeout=PresenceCore.PING_TIMEOUT, quiet=True)

                              if received == 0:
                                      wifi.wifi.Wifi.lan_disconnected()
                              else:
                                      wifi.wifi.Wifi.lan_connected()

                      presents = []
                      current_detected = None
                      smartphone_in_list = False

                      for smartphone in presence_config.smartphones:
                              # If smartphone present
                              if smartphone != b"":
                                      smartphone_in_list = True

                                      # Ping smartphone
                                      sent,received,success = await server.ping.async_ping(smartphone, count=PresenceCore.PING_COUNT, timeout=PresenceCore.PING_TIMEOUT, quiet=True)

                                      # If a response received from smartphone
                                      if received > 0:
                                              presents.append(smartphone)
                                              PresenceCore.last_time = time.time()
                                              current_detected = True
                                              wifi.wifi.Wifi.lan_connected()

                      # If no smartphones detected during a very long time
                      if PresenceCore.last_time + PresenceCore.ABSENCE_TIMEOUT < time.time():
                              # Nobody in the house
                              current_detected = False

                      # If smartphone detected
                      if current_detected is True:
                              # If no smartphone previously detected
                              if PresenceCore.is_detected() != current_detected:
                                      # Notify the house is not empty
                                      msg = b""
                                      for present in presents:
                                              msg += b"%s "%present
                                      server.notifier.Notifier.notify(topic=tools.topic.presence_detected, value=tools.topic.value_on,  message=tools.lang.presence_of_s%(msg), enabled=presence_config.notify,url=webhook_config.inhabited_house)
                                      PresenceCore.set_detection(True)
                      # If no smartphone detected
                      elif current_detected is False:
                              # If smartphone previously detected
                              if PresenceCore.is_detected() != current_detected:
                                      # Notify the house in empty
                                      server.notifier.Notifier.notify(topic=tools.topic.presence_detected, value=tools.topic.value_off, message=tools.lang.empty_house, enabled=presence_config.notify,url=webhook_config.empty_house)
                                      PresenceCore.set_detection(False)

                      # If all smartphones not responded during a long time
                      if PresenceCore.last_time + PresenceCore.NO_ANSWER_TIMEOUT < time.time() and smartphone_in_list is True:
                              # Set fast polling rate
                              result = False
                      else:
                              # Reduce polling rate
                              result = True
                      return result

  ### Class variables

  `var ABSENCE_TIMEOUT`
  `var DNS_POLLING`
  `var NO_ANSWER_TIMEOUT`
  `var PING_COUNT`
  `var PING_TIMEOUT`
  `var detected`
  `var last_dns_time`
  `var last_time`

  ### Static methods

  `async def detect(presence_config, webhook_config)`

    Detect the presence or not of smartphones

    Expand source code

        @staticmethod
        async def detect(presence_config, webhook_config):
                """ Detect the presence or not of smartphones """
                if PresenceCore.last_dns_time + PresenceCore.DNS_POLLING < time.time():
                        PresenceCore.last_dns_time = time.time()
                        sent,received,success = await server.ping.async_ping(wifi.wifi.Wifi.get_dns(), count=PresenceCore.PING_COUNT, timeout=PresenceCore.PING_TIMEOUT, quiet=True)

                        if received == 0:
                                wifi.wifi.Wifi.lan_disconnected()
                        else:
                                wifi.wifi.Wifi.lan_connected()

                presents = []
                current_detected = None
                smartphone_in_list = False

                for smartphone in presence_config.smartphones:
                        # If smartphone present
                        if smartphone != b"":
                                smartphone_in_list = True

                                # Ping smartphone
                                sent,received,success = await server.ping.async_ping(smartphone, count=PresenceCore.PING_COUNT, timeout=PresenceCore.PING_TIMEOUT, quiet=True)

                                # If a response received from smartphone
                                if received > 0:
                                        presents.append(smartphone)
                                        PresenceCore.last_time = time.time()
                                        current_detected = True
                                        wifi.wifi.Wifi.lan_connected()

                # If no smartphones detected during a very long time
                if PresenceCore.last_time + PresenceCore.ABSENCE_TIMEOUT < time.time():
                        # Nobody in the house
                        current_detected = False

                # If smartphone detected
                if current_detected is True:
                        # If no smartphone previously detected
                        if PresenceCore.is_detected() != current_detected:
                                # Notify the house is not empty
                                msg = b""
                                for present in presents:
                                        msg += b"%s "%present
                                server.notifier.Notifier.notify(topic=tools.topic.presence_detected, value=tools.topic.value_on,  message=tools.lang.presence_of_s%(msg), enabled=presence_config.notify,url=webhook_config.inhabited_house)
                                PresenceCore.set_detection(True)
                # If no smartphone detected
                elif current_detected is False:
                        # If smartphone previously detected
                        if PresenceCore.is_detected() != current_detected:
                                # Notify the house in empty
                                server.notifier.Notifier.notify(topic=tools.topic.presence_detected, value=tools.topic.value_off, message=tools.lang.empty_house, enabled=presence_config.notify,url=webhook_config.empty_house)
                                PresenceCore.set_detection(False)

                # If all smartphones not responded during a long time
                if PresenceCore.last_time + PresenceCore.NO_ANSWER_TIMEOUT < time.time() and smartphone_in_list is True:
                        # Set fast polling rate
                        result = False
                else:
                        # Reduce polling rate
                        result = True
                return result

  `def is_detected()`

    Indicates if presence detected

    Expand source code

        @staticmethod
        def is_detected():
                """ Indicates if presence detected """
                return PresenceCore.detected[0]

  `def set_detection(state)`

    Force presence detection

    Expand source code

        @staticmethod
        def set_detection(state):
                """ Force presence detection """
                PresenceCore.detected[0] = state