Exemple #1
0
    def process_ws_packet(
            self,
            packet: WSPacket,
            models: Optional[Set[ModelType]] = None,
            ignore_stats: bool = False) -> Optional[WSSubscriptionMessage]:
        if models is None:
            models = set()

        if not isinstance(packet.action_frame, WSJSONPacketFrame):
            _LOGGER.debug("Unexpected action frame format: %s",
                          packet.action_frame.payload_format)

        if not isinstance(packet.data_frame, WSJSONPacketFrame):
            _LOGGER.debug("Unexpected data frame format: %s",
                          packet.data_frame.payload_format)

        action, data = self._get_frame_data(packet)
        if action["newUpdateId"] is not None:
            self.last_update_id = UUID(action["newUpdateId"])

        if action["modelKey"] not in ModelType.values():
            _LOGGER.debug("Unknown model type: %s", action["modelKey"])
            self._create_stat(packet, [], True)
            return None

        if len(models) > 0 and ModelType(
                action["modelKey"]) not in models or len(data) == 0:
            self._create_stat(packet, [], True)
            return None

        if action["action"] == "add":
            return self._process_add_packet(packet, data)

        if action["action"] == "update":
            if action["modelKey"] == ModelType.NVR.value:
                return self._process_nvr_update(packet, data, ignore_stats)
            if action["modelKey"] in ModelType.bootstrap_models(
            ) or action["modelKey"] == ModelType.EVENT.value:
                return self._process_device_update(packet, action, data,
                                                   ignore_stats)
            _LOGGER.debug("Unexpected bootstrap model type for update: %s",
                          action["modelKey"])

        self._create_stat(packet, [], True)
        return None
Exemple #2
0
    def unifi_dict_to_dict(cls, data: Dict[str, Any]) -> Dict[str, Any]:
        for model_type in ModelType.bootstrap_models():
            key = model_type + "s"
            items: Dict[str, ProtectModel] = {}
            for item in data[key]:
                items[item["id"]] = item
            data[key] = items

        return super().unifi_dict_to_dict(data)
Exemple #3
0
    def unifi_dict(self, data: Optional[Dict[str, Any]] = None, exclude: Optional[Set[str]] = None) -> Dict[str, Any]:
        data = super().unifi_dict(data=data, exclude=exclude)

        if "events" in data:
            del data["events"]

        for model_type in ModelType.bootstrap_models():
            attr = model_type + "s"
            if attr in data and isinstance(data[attr], dict):
                data[attr] = list(data[attr].values())

        return data
Exemple #4
0
    def unifi_dict_to_dict(cls, data: Dict[str, Any]) -> Dict[str, Any]:
        api = cls._get_api(data.get("api"))
        for model_type in ModelType.bootstrap_models():
            key = model_type + "s"
            items: Dict[str, ProtectModel] = {}
            for item in data[key]:
                if api is not None and api.ignore_unadopted and not item.get(
                        "isAdopted", True):
                    continue

                items[item["id"]] = item
            data[key] = items

        return super().unifi_dict_to_dict(data)
Exemple #5
0
def get_klass_from_dict(data: Dict[str, Any]) -> Type[ProtectModel]:
    """
    Helper method to read the `modelKey` from a UFP JSON dict and get the correct Python class for conversion.
    Will raise `DataDecodeError` if the `modelKey` is for an unknown object.
    """
    if "modelKey" not in data:
        raise DataDecodeError("No modelKey")

    model = ModelType(data["modelKey"])

    klass = MODEL_TO_CLASS.get(model)

    if klass is None:
        raise DataDecodeError("Unknown modelKey")

    return klass
Exemple #6
0
    def _process_add_packet(
            self, packet: WSPacket,
            data: Dict[str, Any]) -> Optional[WSSubscriptionMessage]:
        obj = create_from_unifi_dict(data, api=self._api)

        if isinstance(obj, Event):
            self.process_event(obj)
        elif isinstance(obj, NVR):
            self.nvr = obj
        elif (isinstance(obj, ProtectModelWithId) and obj.model is not None
              and obj.model.value in ModelType.bootstrap_models()):
            key = obj.model.value + "s"
            getattr(self, key)[obj.id] = obj
        else:
            _LOGGER.debug("Unexpected bootstrap model type for add: %s",
                          obj.model)
            return None

        updated = obj.dict()
        self._create_stat(packet, list(updated.keys()), False)
        return WSSubscriptionMessage(action=WSAction.ADD,
                                     new_update_id=self.last_update_id,
                                     changed_data=updated,
                                     new_obj=obj)
Exemple #7
0
    def process_ws_packet(self, packet: WSPacket) -> Optional[WSSubscriptionMessage]:
        if not isinstance(packet.action_frame, WSJSONPacketFrame):
            _LOGGER.debug("Unexpected action frame format: %s", packet.action_frame.payload_format)

        if not isinstance(packet.data_frame, WSJSONPacketFrame):
            _LOGGER.debug("Unexpected data frame format: %s", packet.data_frame.payload_format)

        action: dict = packet.action_frame.data  # type: ignore
        data: dict = packet.data_frame.data  # type: ignore
        if action["newUpdateId"] is not None:
            self.last_update_id = UUID(action["newUpdateId"])

        if action["modelKey"] not in ModelType.values():
            _LOGGER.debug("Unknown model type: %s", action["modelKey"])
            return None

        if action["action"] == "add":
            obj = create_from_unifi_dict(data, api=self._api)

            if isinstance(obj, Event):
                self.process_event(obj)
            elif isinstance(obj, NVR):
                self.nvr = obj
            elif (
                isinstance(obj, ProtectModelWithId)
                and obj.model is not None
                and obj.model.value in ModelType.bootstrap_models()
            ):
                key = obj.model.value + "s"
                getattr(self, key)[obj.id] = obj
            else:
                _LOGGER.debug("Unexpected bootstrap model type for add: %s", obj.model)

            return WSSubscriptionMessage(
                action=WSAction.ADD, new_update_id=self.last_update_id, changed_data=obj.dict(), new_obj=obj
            )

        if action["action"] == "update":
            model_type = action["modelKey"]
            if model_type == ModelType.NVR.value:
                data = self.nvr.unifi_dict_to_dict(data)
                old_nvr = self.nvr.copy()
                self.nvr = self.nvr.update_from_dict(deepcopy(data))

                return WSSubscriptionMessage(
                    action=WSAction.UPDATE,
                    new_update_id=self.last_update_id,
                    changed_data=data,
                    new_obj=self.nvr,
                    old_obj=old_nvr,
                )
            if model_type in ModelType.bootstrap_models() or model_type == ModelType.EVENT.value:
                key = model_type + "s"
                devices = getattr(self, key)
                if action["id"] in devices:
                    obj: ProtectModel = devices[action["id"]]
                    data = obj.unifi_dict_to_dict(data)
                    old_obj = obj.copy()
                    obj = obj.update_from_dict(deepcopy(data))

                    if isinstance(obj, Event):
                        self.process_event(obj)

                    devices[action["id"]] = obj

                    return WSSubscriptionMessage(
                        action=WSAction.UPDATE,
                        new_update_id=self.last_update_id,
                        changed_data=data,
                        new_obj=obj,
                        old_obj=old_obj,
                    )

                # ignore updates to events that phase out
                if model_type != ModelType.EVENT.value:
                    _LOGGER.debug("Unexpected %s: %s", key, action["id"])
            else:
                _LOGGER.debug("Unexpected bootstrap model type for update: %s", model_type)

        return None