pydglab-ws


Namepydglab-ws JSON
Version 1.0.2 PyPI version JSON
download
home_pagehttps://pydglab-ws.readthedocs.io
Summary一个通过 WebSocket 控制郊狼 DG-Lab 的 Python 库
upload_time2024-05-20 06:36:35
maintainerNone
docs_urlNone
authorLjzd-PRO
requires_python>=3.8
licenseNone
keywords dg-lab dg-lab-v3 websocket library os-independent
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            <h1 align="center">
  PyDGLab-WS
</h1>

<p align="center">
  一个用于创建郊狼 3.0 DG-Lab App Socket 控制终端和服务端的 Python 库
</p>

<p align="center">
  <a href="https://pydglab-ws.readthedocs.io">📖 完整文档</a>
</p>

<p align="center">
  <a href="https://www.codefactor.io/repository/github/ljzd-pro/pydglab-ws">
    <img src="https://www.codefactor.io/repository/github/ljzd-pro/pydglab-ws/badge" alt="CodeFactor" />
  </a>

  <a href="https://codecov.io/gh/Ljzd-PRO/PyDGLab-WS" target="_blank">
      <img src="https://codecov.io/gh/Ljzd-PRO/PyDGLab-WS/branch/master/graph/badge.svg?token=VTr0LB1yWF" alt="codecov"/>
  </a>

  <a href="https://github.com/Ljzd-PRO/PyDGLab-WS/actions/workflows/codecov.yml" target="_blank">
    <img alt="Test Result" src="https://img.shields.io/github/actions/workflow/status/Ljzd-PRO/PyDGLab-WS/codecov.yml">
  </a>

  <a href='https://pydglab-ws.readthedocs.io/'>
    <img src='https://readthedocs.org/projects/pydglab-ws/badge/?version=latest' alt='Documentation Status' />
  </a>

  <a href="https://github.com/Ljzd-PRO/PyDGLab-WS/activity">
    <img src="https://img.shields.io/github/last-commit/Ljzd-PRO/PyDGLab-WS/master" alt="Last Commit"/>
  </a>

  <a href="./LICENSE">
    <img src="https://img.shields.io/github/license/Ljzd-PRO/PyDGLab-WS" alt="BSD 3-Clause"/>
  </a>

  <a href="https://pypi.org/project/pydglab-ws" target="_blank">
    <img src="https://img.shields.io/github/v/release/Ljzd-PRO/PyDGLab-WS?logo=python" alt="Version">
  </a>
</p>

## 💡 特性

- 通过该库可开发 Python 程序,接入 DG-Lab App
- 完全使用 asyncio 异步,并发执行各项操作
- 可部署第三方终端与 Socket 服务一体的服务端,降低部署复杂度和延迟
- 使用异步生成器、上下文管理器等,结合语言特性
- 通过 Pydantic, 枚举 管理消息结构和常量,便于开发

### 🔧 DG-Lab App 的 Socket 被控功能支持的操作

- 获取 A, B 通道强度 以及 通道强度上限 的数据更新
- 对 A, B 通道强度进行操作,支持增加、减少、设定到指定值
- 向 App 发送持续一段时间的波形操作数据
- 清空 App 波形操作队列
- 获取 App 按下反馈按钮的通知

## 🚀 快速开始

📖 更多用法和完整 API 请查看文档:https://pydglab-ws.readthedocs.io

> [!Note]
> 注意,您可能需要先大致了解一下第三方终端通过 WebSocket 连接控制 DG-Lab App 的基本流程和原理 \
> 官方文档:https://github.com/DG-LAB-OPENSOURCE/DG-LAB-OPENSOURCE/blob/main/socket/README.md

### 🔨 安装

```bash
pip3 install pydglab-ws
```

### 📡 搭建服务端

```python3
import asyncio
from pydglab_ws.server import DGLabWSServer


async def main():
    async with DGLabWSServer("0.0.0.0", 5678, 60) as server:
        while True:
            print(f"已连接的 WebSocket 客户端(终端/App):{list(server.uuid_to_ws.keys())}")
            print(f"已连接的本地终端:{list(server.local_client_ids)}")
            print(f"关系绑定:{server.client_id_to_target_id}")
            await asyncio.sleep(5)


if __name__ == "__main__":
    asyncio.run(main())
```

更多演示请查看 [`examples/server.py`](examples/server.py)

### 🕹️ 搭建客户端 / 第三方终端

当进入 `DGLabWSServer` 的异步生成器时,从 WebSocket 服务端获取 `clientId` 的操作会 **自动完成**

```python3
import asyncio
from websockets import ConnectionClosedOK
from pydglab_ws import DGLabWSConnect


def print_qrcode(_: str):
    """输出二维码到终端界面"""
    ...


async def main():
    try:
        async with DGLabWSConnect("ws://192.168.1.161:5678") as client:
            # 获取二维码
            url = client.get_qrcode()
            print("请用 DG-Lab App 扫描二维码以连接")
            print_qrcode(url)

            # 等待绑定
            await client.bind()
            print(f"已与 App {client.target_id} 成功绑定")

            # 从 App 接收数据更新,并进行远控操作
            async for data in client.data_generator():
                print(f"收取到数据:{data}")
    except ConnectionClosedOK:
        print("Socket 服务端断开连接")


if __name__ == "__main__":
    asyncio.run(main())
```

更多演示请查看 [`examples/ws_client.py`](examples/ws_client.py)

### 🕹️ 搭建与第三方终端一体的 WebSocket 服务端

这段代码不仅提供 DG-Lab WebSocket 服务端服务,还生成了一个本地终端可供 App 连接。

> [!Tip]
> 不管是本地终端 `DGLabLocalClient` 还是 WebSocket 终端 `DGLabWSClient`,**包含的主要方法都相同** \
> 因此在该段代码中,终端相关的逻辑与上面的独立的 WebSocket 终端的实现基本相同。 \
> 这种方式,省去了终端连接 WebSocket 服务端的环节,终端与 WebSocket 服务端一体,**网络延迟更低,部署更方便**。

```python3
import asyncio
from pydglab_ws import DGLabWSServer


def print_qrcode(_: str):
    """输出二维码到终端界面"""
    ...


async def main():
    async with DGLabWSServer("0.0.0.0", 5678, 60) as server:
        client = server.new_local_client()

        url = client.get_qrcode("ws://192.168.1.161:5678")
        print("请用 DG-Lab App 扫描二维码以连接")
        print_qrcode(url)

        # 等待绑定
        await client.bind()
        print(f"已与 App {client.target_id} 成功绑定")

        # 从 App 接收数据更新,并进行远控操作
        async for data in client.data_generator():
            print(f"收取到数据:{data}")


if __name__ == "__main__":
    asyncio.run(main())

```

更多演示请查看 [`examples/local_client_with_server.py`](examples/server_with_local_client.py)

## 📌 更多

### 🔗 链接

- PyPI: 🔗[pydglab-ws](https://pypi.org/project/pydglab-ws/)

### 📐 代码覆盖率

![codecov.io](https://codecov.io/github/Ljzd-PRO/PyDGLab-WS/graphs/tree.svg?token=VTr0LB1yWF)

### 许可证

PyDGLab-WS 使用 BSD 3-Clause 许可证.

Copyright © 2024 by Ljzd-PRO.

            

Raw data

            {
    "_id": null,
    "home_page": "https://pydglab-ws.readthedocs.io",
    "name": "pydglab-ws",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "dg-lab, dg-lab-v3, websocket, library, os-independent",
    "author": "Ljzd-PRO",
    "author_email": "ljzd@office.ljzd-pro.asia",
    "download_url": "https://files.pythonhosted.org/packages/f4/35/7947c06b6911e74eb16461a02a0eb9fa862da763c9ca0f9efbe8c10f458b/pydglab_ws-1.0.2.tar.gz",
    "platform": null,
    "description": "<h1 align=\"center\">\n  PyDGLab-WS\n</h1>\n\n<p align=\"center\">\n  \u4e00\u4e2a\u7528\u4e8e\u521b\u5efa\u90ca\u72fc 3.0 DG-Lab App Socket \u63a7\u5236\u7ec8\u7aef\u548c\u670d\u52a1\u7aef\u7684 Python \u5e93\n</p>\n\n<p align=\"center\">\n  <a href=\"https://pydglab-ws.readthedocs.io\">\ud83d\udcd6 \u5b8c\u6574\u6587\u6863</a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.codefactor.io/repository/github/ljzd-pro/pydglab-ws\">\n    <img src=\"https://www.codefactor.io/repository/github/ljzd-pro/pydglab-ws/badge\" alt=\"CodeFactor\" />\n  </a>\n\n  <a href=\"https://codecov.io/gh/Ljzd-PRO/PyDGLab-WS\" target=\"_blank\">\n      <img src=\"https://codecov.io/gh/Ljzd-PRO/PyDGLab-WS/branch/master/graph/badge.svg?token=VTr0LB1yWF\" alt=\"codecov\"/>\n  </a>\n\n  <a href=\"https://github.com/Ljzd-PRO/PyDGLab-WS/actions/workflows/codecov.yml\" target=\"_blank\">\n    <img alt=\"Test Result\" src=\"https://img.shields.io/github/actions/workflow/status/Ljzd-PRO/PyDGLab-WS/codecov.yml\">\n  </a>\n\n  <a href='https://pydglab-ws.readthedocs.io/'>\n    <img src='https://readthedocs.org/projects/pydglab-ws/badge/?version=latest' alt='Documentation Status' />\n  </a>\n\n  <a href=\"https://github.com/Ljzd-PRO/PyDGLab-WS/activity\">\n    <img src=\"https://img.shields.io/github/last-commit/Ljzd-PRO/PyDGLab-WS/master\" alt=\"Last Commit\"/>\n  </a>\n\n  <a href=\"./LICENSE\">\n    <img src=\"https://img.shields.io/github/license/Ljzd-PRO/PyDGLab-WS\" alt=\"BSD 3-Clause\"/>\n  </a>\n\n  <a href=\"https://pypi.org/project/pydglab-ws\" target=\"_blank\">\n    <img src=\"https://img.shields.io/github/v/release/Ljzd-PRO/PyDGLab-WS?logo=python\" alt=\"Version\">\n  </a>\n</p>\n\n## \ud83d\udca1 \u7279\u6027\n\n- \u901a\u8fc7\u8be5\u5e93\u53ef\u5f00\u53d1 Python \u7a0b\u5e8f\uff0c\u63a5\u5165 DG-Lab App\n- \u5b8c\u5168\u4f7f\u7528 asyncio \u5f02\u6b65\uff0c\u5e76\u53d1\u6267\u884c\u5404\u9879\u64cd\u4f5c\n- \u53ef\u90e8\u7f72\u7b2c\u4e09\u65b9\u7ec8\u7aef\u4e0e Socket \u670d\u52a1\u4e00\u4f53\u7684\u670d\u52a1\u7aef\uff0c\u964d\u4f4e\u90e8\u7f72\u590d\u6742\u5ea6\u548c\u5ef6\u8fdf\n- \u4f7f\u7528\u5f02\u6b65\u751f\u6210\u5668\u3001\u4e0a\u4e0b\u6587\u7ba1\u7406\u5668\u7b49\uff0c\u7ed3\u5408\u8bed\u8a00\u7279\u6027\n- \u901a\u8fc7 Pydantic, \u679a\u4e3e \u7ba1\u7406\u6d88\u606f\u7ed3\u6784\u548c\u5e38\u91cf\uff0c\u4fbf\u4e8e\u5f00\u53d1\n\n### \ud83d\udd27 DG-Lab App \u7684 Socket \u88ab\u63a7\u529f\u80fd\u652f\u6301\u7684\u64cd\u4f5c\n\n- \u83b7\u53d6 A, B \u901a\u9053\u5f3a\u5ea6 \u4ee5\u53ca \u901a\u9053\u5f3a\u5ea6\u4e0a\u9650 \u7684\u6570\u636e\u66f4\u65b0\n- \u5bf9 A, B \u901a\u9053\u5f3a\u5ea6\u8fdb\u884c\u64cd\u4f5c\uff0c\u652f\u6301\u589e\u52a0\u3001\u51cf\u5c11\u3001\u8bbe\u5b9a\u5230\u6307\u5b9a\u503c\n- \u5411 App \u53d1\u9001\u6301\u7eed\u4e00\u6bb5\u65f6\u95f4\u7684\u6ce2\u5f62\u64cd\u4f5c\u6570\u636e\n- \u6e05\u7a7a App \u6ce2\u5f62\u64cd\u4f5c\u961f\u5217\n- \u83b7\u53d6 App \u6309\u4e0b\u53cd\u9988\u6309\u94ae\u7684\u901a\u77e5\n\n## \ud83d\ude80 \u5feb\u901f\u5f00\u59cb\n\n\ud83d\udcd6 \u66f4\u591a\u7528\u6cd5\u548c\u5b8c\u6574 API \u8bf7\u67e5\u770b\u6587\u6863\uff1ahttps://pydglab-ws.readthedocs.io\n\n> [!Note]\n> \u6ce8\u610f\uff0c\u60a8\u53ef\u80fd\u9700\u8981\u5148\u5927\u81f4\u4e86\u89e3\u4e00\u4e0b\u7b2c\u4e09\u65b9\u7ec8\u7aef\u901a\u8fc7 WebSocket \u8fde\u63a5\u63a7\u5236 DG-Lab App \u7684\u57fa\u672c\u6d41\u7a0b\u548c\u539f\u7406 \\\n> \u5b98\u65b9\u6587\u6863\uff1ahttps://github.com/DG-LAB-OPENSOURCE/DG-LAB-OPENSOURCE/blob/main/socket/README.md\n\n### \ud83d\udd28 \u5b89\u88c5\n\n```bash\npip3 install pydglab-ws\n```\n\n### \ud83d\udce1 \u642d\u5efa\u670d\u52a1\u7aef\n\n```python3\nimport asyncio\nfrom pydglab_ws.server import DGLabWSServer\n\n\nasync def main():\n    async with DGLabWSServer(\"0.0.0.0\", 5678, 60) as server:\n        while True:\n            print(f\"\u5df2\u8fde\u63a5\u7684 WebSocket \u5ba2\u6237\u7aef\uff08\u7ec8\u7aef/App\uff09\uff1a{list(server.uuid_to_ws.keys())}\")\n            print(f\"\u5df2\u8fde\u63a5\u7684\u672c\u5730\u7ec8\u7aef\uff1a{list(server.local_client_ids)}\")\n            print(f\"\u5173\u7cfb\u7ed1\u5b9a\uff1a{server.client_id_to_target_id}\")\n            await asyncio.sleep(5)\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n\u66f4\u591a\u6f14\u793a\u8bf7\u67e5\u770b [`examples/server.py`](examples/server.py)\n\n### \ud83d\udd79\ufe0f \u642d\u5efa\u5ba2\u6237\u7aef / \u7b2c\u4e09\u65b9\u7ec8\u7aef\n\n\u5f53\u8fdb\u5165 `DGLabWSServer` \u7684\u5f02\u6b65\u751f\u6210\u5668\u65f6\uff0c\u4ece WebSocket \u670d\u52a1\u7aef\u83b7\u53d6 `clientId` \u7684\u64cd\u4f5c\u4f1a **\u81ea\u52a8\u5b8c\u6210**\n\n```python3\nimport asyncio\nfrom websockets import ConnectionClosedOK\nfrom pydglab_ws import DGLabWSConnect\n\n\ndef print_qrcode(_: str):\n    \"\"\"\u8f93\u51fa\u4e8c\u7ef4\u7801\u5230\u7ec8\u7aef\u754c\u9762\"\"\"\n    ...\n\n\nasync def main():\n    try:\n        async with DGLabWSConnect(\"ws://192.168.1.161:5678\") as client:\n            # \u83b7\u53d6\u4e8c\u7ef4\u7801\n            url = client.get_qrcode()\n            print(\"\u8bf7\u7528 DG-Lab App \u626b\u63cf\u4e8c\u7ef4\u7801\u4ee5\u8fde\u63a5\")\n            print_qrcode(url)\n\n            # \u7b49\u5f85\u7ed1\u5b9a\n            await client.bind()\n            print(f\"\u5df2\u4e0e App {client.target_id} \u6210\u529f\u7ed1\u5b9a\")\n\n            # \u4ece App \u63a5\u6536\u6570\u636e\u66f4\u65b0\uff0c\u5e76\u8fdb\u884c\u8fdc\u63a7\u64cd\u4f5c\n            async for data in client.data_generator():\n                print(f\"\u6536\u53d6\u5230\u6570\u636e\uff1a{data}\")\n    except ConnectionClosedOK:\n        print(\"Socket \u670d\u52a1\u7aef\u65ad\u5f00\u8fde\u63a5\")\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n\u66f4\u591a\u6f14\u793a\u8bf7\u67e5\u770b [`examples/ws_client.py`](examples/ws_client.py)\n\n### \ud83d\udd79\ufe0f \u642d\u5efa\u4e0e\u7b2c\u4e09\u65b9\u7ec8\u7aef\u4e00\u4f53\u7684 WebSocket \u670d\u52a1\u7aef\n\n\u8fd9\u6bb5\u4ee3\u7801\u4e0d\u4ec5\u63d0\u4f9b DG-Lab WebSocket \u670d\u52a1\u7aef\u670d\u52a1\uff0c\u8fd8\u751f\u6210\u4e86\u4e00\u4e2a\u672c\u5730\u7ec8\u7aef\u53ef\u4f9b App \u8fde\u63a5\u3002\n\n> [!Tip]\n> \u4e0d\u7ba1\u662f\u672c\u5730\u7ec8\u7aef `DGLabLocalClient` \u8fd8\u662f WebSocket \u7ec8\u7aef `DGLabWSClient`\uff0c**\u5305\u542b\u7684\u4e3b\u8981\u65b9\u6cd5\u90fd\u76f8\u540c** \\\n> \u56e0\u6b64\u5728\u8be5\u6bb5\u4ee3\u7801\u4e2d\uff0c\u7ec8\u7aef\u76f8\u5173\u7684\u903b\u8f91\u4e0e\u4e0a\u9762\u7684\u72ec\u7acb\u7684 WebSocket \u7ec8\u7aef\u7684\u5b9e\u73b0\u57fa\u672c\u76f8\u540c\u3002 \\\n> \u8fd9\u79cd\u65b9\u5f0f\uff0c\u7701\u53bb\u4e86\u7ec8\u7aef\u8fde\u63a5 WebSocket \u670d\u52a1\u7aef\u7684\u73af\u8282\uff0c\u7ec8\u7aef\u4e0e WebSocket \u670d\u52a1\u7aef\u4e00\u4f53\uff0c**\u7f51\u7edc\u5ef6\u8fdf\u66f4\u4f4e\uff0c\u90e8\u7f72\u66f4\u65b9\u4fbf**\u3002\n\n```python3\nimport asyncio\nfrom pydglab_ws import DGLabWSServer\n\n\ndef print_qrcode(_: str):\n    \"\"\"\u8f93\u51fa\u4e8c\u7ef4\u7801\u5230\u7ec8\u7aef\u754c\u9762\"\"\"\n    ...\n\n\nasync def main():\n    async with DGLabWSServer(\"0.0.0.0\", 5678, 60) as server:\n        client = server.new_local_client()\n\n        url = client.get_qrcode(\"ws://192.168.1.161:5678\")\n        print(\"\u8bf7\u7528 DG-Lab App \u626b\u63cf\u4e8c\u7ef4\u7801\u4ee5\u8fde\u63a5\")\n        print_qrcode(url)\n\n        # \u7b49\u5f85\u7ed1\u5b9a\n        await client.bind()\n        print(f\"\u5df2\u4e0e App {client.target_id} \u6210\u529f\u7ed1\u5b9a\")\n\n        # \u4ece App \u63a5\u6536\u6570\u636e\u66f4\u65b0\uff0c\u5e76\u8fdb\u884c\u8fdc\u63a7\u64cd\u4f5c\n        async for data in client.data_generator():\n            print(f\"\u6536\u53d6\u5230\u6570\u636e\uff1a{data}\")\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n\n```\n\n\u66f4\u591a\u6f14\u793a\u8bf7\u67e5\u770b [`examples/local_client_with_server.py`](examples/server_with_local_client.py)\n\n## \ud83d\udccc \u66f4\u591a\n\n### \ud83d\udd17 \u94fe\u63a5\n\n- PyPI: \ud83d\udd17[pydglab-ws](https://pypi.org/project/pydglab-ws/)\n\n### \ud83d\udcd0 \u4ee3\u7801\u8986\u76d6\u7387\n\n![codecov.io](https://codecov.io/github/Ljzd-PRO/PyDGLab-WS/graphs/tree.svg?token=VTr0LB1yWF)\n\n### \u8bb8\u53ef\u8bc1\n\nPyDGLab-WS \u4f7f\u7528 BSD 3-Clause \u8bb8\u53ef\u8bc1.\n\nCopyright \u00a9 2024 by Ljzd-PRO.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "\u4e00\u4e2a\u901a\u8fc7 WebSocket \u63a7\u5236\u90ca\u72fc DG-Lab \u7684 Python \u5e93",
    "version": "1.0.2",
    "project_urls": {
        "Documentation": "https://pydglab-ws.readthedocs.io",
        "Homepage": "https://pydglab-ws.readthedocs.io",
        "Repository": "https://github.com/Ljzd-PRO/PyDGLab-WS"
    },
    "split_keywords": [
        "dg-lab",
        " dg-lab-v3",
        " websocket",
        " library",
        " os-independent"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9626192ebc02506b8e0f051b40a6c4e9d4d266914387b0bc1371655453691911",
                "md5": "12e1c6442ab8c99ccffba9225eaccd58",
                "sha256": "f259e7b24d990e654753229b33b4d0123b9e85e35493a84c3f173ad05e19131a"
            },
            "downloads": -1,
            "filename": "pydglab_ws-1.0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "12e1c6442ab8c99ccffba9225eaccd58",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 20416,
            "upload_time": "2024-05-20T06:36:34",
            "upload_time_iso_8601": "2024-05-20T06:36:34.203463Z",
            "url": "https://files.pythonhosted.org/packages/96/26/192ebc02506b8e0f051b40a6c4e9d4d266914387b0bc1371655453691911/pydglab_ws-1.0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f4357947c06b6911e74eb16461a02a0eb9fa862da763c9ca0f9efbe8c10f458b",
                "md5": "4efd0021931438954ff4c2f7c652fa29",
                "sha256": "83f74c398ca09b2e14de902a84c5997d94f5ac24e8ba2d0f1cc2d39acdea9421"
            },
            "downloads": -1,
            "filename": "pydglab_ws-1.0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "4efd0021931438954ff4c2f7c652fa29",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 17537,
            "upload_time": "2024-05-20T06:36:35",
            "upload_time_iso_8601": "2024-05-20T06:36:35.436038Z",
            "url": "https://files.pythonhosted.org/packages/f4/35/7947c06b6911e74eb16461a02a0eb9fa862da763c9ca0f9efbe8c10f458b/pydglab_ws-1.0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-20 06:36:35",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Ljzd-PRO",
    "github_project": "PyDGLab-WS",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "lcname": "pydglab-ws"
}
        
Elapsed time: 0.26085s