def _handle_ws_message(self, msg: aiohttp.WSMessage) -> None: if not self._record_listen_for_events: return now = time.monotonic() self._record_num_ws += 1 time_offset = now - self._record_ws_start_time if msg.type == aiohttp.WSMsgType.BINARY: packet = WSPacket(msg.data) if not isinstance(packet.action_frame, WSJSONPacketFrame): typer.secho(f"Got non-JSON action frame: {packet.action_frame.payload_format}", fg="yellow") return if not isinstance(packet.data_frame, WSJSONPacketFrame): typer.secho(f"Got non-JSON data frame: {packet.data_frame.payload_format}", fg="yellow") return if self.anonymize: packet.action_frame.data = anonymize_data(packet.action_frame.data) packet.data_frame.data = anonymize_data(packet.data_frame.data) packet.pack_frames() self._record_ws_messages[str(time_offset)] = { "raw": packet.raw_base64, "action": packet.action_frame.data, "data": packet.data_frame.data, } else: typer.secho(f"Got non-binary message: {msg.type}", fg="yellow")
async def test_ws_emit_alarm_callback( mock_now, protect_client_no_debug: ProtectApiClient, now: datetime, sensor, packet: WSPacket ): mock_now.return_value = now protect_client = protect_client_no_debug protect_client.emit_message = Mock() # type: ignore obj = protect_client.bootstrap.sensors[sensor["id"]] expected_updated_id = "0441ecc6-f0fa-4b19-b071-7987c143138a" action_frame: WSJSONPacketFrame = packet.action_frame # type: ignore action_frame.data = { "action": "update", "newUpdateId": expected_updated_id, "modelKey": "sensor", "id": sensor["id"], } data_frame: WSJSONPacketFrame = packet.data_frame # type: ignore data_frame.data = {"alarmTriggeredAt": to_js_time(now)} msg = MagicMock() msg.data = packet.pack_frames() assert not obj.is_alarm_detected with patch("pyunifiprotect.data.bootstrap.utc_now", mock_now): protect_client._process_ws_message(msg) assert obj.is_alarm_detected mock_now.return_value = utc_now() + EVENT_PING_INTERVAL assert not obj.is_alarm_detected protect_client.emit_message.assert_called_once()
async def test_ws_event_smart(protect_client_no_debug: ProtectApiClient, now, camera, packet: WSPacket): protect_client = protect_client_no_debug def get_camera(): return protect_client.bootstrap.cameras[camera["id"]] bootstrap_before = protect_client.bootstrap.unifi_dict() camera_before = get_camera().copy() expected_updated_id = "0441ecc6-f0fa-4b19-b071-7987c143138a" expected_event_id = "bf9a241afe74821ceffffd05" action_frame: WSJSONPacketFrame = packet.action_frame # type: ignore action_frame.data["newUpdateId"] = expected_updated_id data_frame: WSJSONPacketFrame = packet.data_frame # type: ignore data_frame.data = { "id": expected_event_id, "type": "smartDetectZone", "start": to_js_time(now - timedelta(seconds=30)), "end": to_js_time(now), "score": 0, "smartDetectTypes": ["person"], "smartDetectEvents": [], "camera": camera["id"], "partition": None, "user": None, "metadata": {}, "thumbnail": f"e-{expected_event_id}", "heatmap": f"e-{expected_event_id}", "modelKey": "event", } msg = MagicMock() msg.data = packet.pack_frames() protect_client._process_ws_message(msg) bootstrap_before["lastUpdateId"] = expected_updated_id bootstrap = protect_client.bootstrap.unifi_dict() camera = get_camera() smart_event = camera.last_smart_detect_event camera.last_smart_detect_event_id = None camera_before.last_smart_detect_event_id = None assert bootstrap == bootstrap_before assert camera.dict() == camera_before.dict() assert smart_event.id == expected_event_id assert smart_event.type == EventType.SMART_DETECT assert smart_event.thumbnail_id == f"e-{expected_event_id}" assert smart_event.heatmap_id == f"e-{expected_event_id}" assert smart_event.start == (now - timedelta(seconds=30)) assert smart_event.end == now for channel in camera.channels: assert channel._api is not None
async def test_ws_event_update(protect_client_no_debug: ProtectApiClient, now, camera, packet: WSPacket): protect_client = protect_client_no_debug def get_camera() -> Camera: return protect_client.bootstrap.cameras[camera["id"]] bootstrap_before = protect_client.bootstrap.unifi_dict() camera_before = get_camera().copy() new_stats = camera_before.stats.unifi_dict() new_stats["rxBytes"] += 100 new_stats["txBytes"] += 100 new_stats["video"]["recordingEnd"] = to_js_time(now) new_stats_unifi = camera_before.unifi_dict( data={"stats": deepcopy(new_stats)}) del new_stats_unifi["stats"]["wifiQuality"] del new_stats_unifi["stats"]["wifiStrength"] expected_updated_id = "0441ecc6-f0fa-4b19-b071-7987c143138a" action_frame: WSJSONPacketFrame = packet.action_frame # type: ignore action_frame.data = { "action": "update", "newUpdateId": expected_updated_id, "modelKey": "camera", "id": camera["id"], } data_frame: WSJSONPacketFrame = packet.data_frame # type: ignore data_frame.data = new_stats_unifi msg = MagicMock() msg.data = packet.pack_frames() protect_client._process_ws_message(msg) camera_index = -1 for index, camera_dict in enumerate(bootstrap_before["cameras"]): if camera_dict["id"] == camera["id"]: camera_index = index break bootstrap_before["cameras"][camera_index]["stats"] = new_stats bootstrap_before["lastUpdateId"] = expected_updated_id bootstrap = protect_client.bootstrap.unifi_dict() assert bootstrap == bootstrap_before