Files
Uni-Lab-OS/unilabos/device_comms/universal_driver.py
Junhan Chang a62a695812 Ready for open source (#47)
* Create app/main API

* create example device

* create ROS backend and example device SDK Wrapper

* Add ROS host and host starting from app.py

* Add gripper device and mock implementation

* add "status_types" & "action_types" to ROS device decorator

* add ActionServer debug example

* [bugfix] complete mock gripper example

* ROS Backend Host for Device action calling and Resource management

* add conda/mamba ENV file

* add host_node communication with app/main.py

* add action message value mappings and converters

* Update ilabos.yaml

* Update issue templates

* example devices.json and resources.json

* Fix Device wrapper to use async property and actions (#7)

* Fix Device wrapper to use async property and actions

* Resolve #1 : support async get methods and actions. Give new examples.

* add both sync/async GRBL controller SDK

* 2 call device actions from appmainpy api to ros hostpy (#8)

* feature: add job

* fix:node start

* feature:add get job status

* fix:get device

* clean

* Resolve #5 device connection diagram and workflow compilation support (#9)

* add syringe pump device and its compilation using device connection diagram

* add RunzeSyringePump real device with ROS2 example

* Prototype machine with 1 pump and 1 CNC

* add ROS2ProtocolNode and related functions

* add ilabos_msgs (to use PumpTransfer action)

* add example device connection graph

* refactor protocol_node code into separate file

* add ROS2SerialNode

* add SerialCommand srv in ilabos_msgs

* add pump_protocol example, and fix bugs

* [fix] serial service: avoid async service deadlock by directly call serial `send_command`

* use SendCmd instead of SingleJointPosition for valve control

* initialize device connection graph when server starts

* Fix #5: async workflow execution (#16)

* add rclpyx and protocol example for async-native workflow

* use async in ROS2ProtocolNode, and host initialization

* add examples of "ros-async" protocol implementation, and `run_in_event_loop` for using native async functions

* use "ros-async" in protocols and device nodes

* fix pump_protocol: push to 0.0 μL

* Envs, docs, and conda recipes (#19)

* update ENV: use python 3.11 and deprecate ros-humble-gazebo-ros

* add ilabos-msgs conda recipe

* Update ilabos.yaml

* fix recipe and env yaml

* Add sphinx docs

* add aichemeco

* add bioyong

* add bioyong

* Support XDL devices & protocols (#20)

* [Feature] support multiple protocols in a single ProtocolNode

* add Junjie's code

* Support "Clean" protocol

* Update Grignard_flow_batchreact_single_pumpvalve.json

* test_grignard_add

* add stir device node and example

* Update device_node.py

add print_publish flag to control the node's log output

* NH4Cl_add

* add "HeaterStirrer" device and "HeatChill" action

* add wait time after each pump action for equilibration

* fix stir

* add Separate protocol

* Refactor Separator device and Stir action

* add rotavap_node

* fix stir

* add chiller node

* Move rinsings into PumpTransfer

* Fix SeparateProtocol under refactored Separator device and Stir action

* Supports automatically add new protocol action_types

* fix PumpTransfer protocol because of rinsing

* Add Rotavap and Chiller devices

* fix SeparateProtocol

* add EvaporateProtocol

* add rotavap devices config

* fix HeaterStirrer and SeparatorController IO

* Fix automatically add new protocol action_types

* Add HeaterStirrer and SeparatorController device config

* fix pump protocols

* Fix Evaporate action

* Update evaporate_protocol.py

* add temp_sensor node and add function remap

* update docs

---------

Co-authored-by: 王俊杰 <1800011822@pku.edu.cn>
Co-authored-by: q434343 <554662886@qq.com>

* fix aichemeco

* [Bugfix] fix Windows conda packaging

* add file upload api

* update dependencies: force to use 3.11 and remove conflict in WIN64 and OSX64

* update dependencies: force to use 3.11 and remove conflict in WIN64 and OSX64

* Create aichemeco_simple.py

* fix

* update

* add aichemeco file

* MQTT [1/2]: action start (#25)

* add mq

* fix

* clean

* add class

* fix excel

* update bioyong

* add api

* fix

---------

Co-authored-by: caok@dp.tech <xiaoyeqiannian@163.com>

* motor & grasp

* Add Grasp motor support and enhance EleGripper class

- Introduced a new motor configuration for Grasp in sjtu.json.
- Updated EleGripper class to inherit from UniversalDriver and added status property.
- Implemented move_and_rotate method for coordinated movement.
- Adjusted threading logic in EleGripper initialization.
- Registered Grasp motor in ROS2 device node configuration.

This commit enhances the motor control capabilities by integrating the Grasp motor and improving the existing EleGripper functionality.

* fix read data lenth

* Update Grasp.py

* MQTT (2/2): publish Device Status, Action Feedback & Results (#27)

* Add bridges in HostNode for device_status publishing

* Add "bridges" selection (fastapi & mqtt) when app start

* add MQ feedback & result publisher, and fix message converter

* fix UUID converting between ROS and MQ

* lint api model.py

* Continuous controllers: PID, MPC, custom controllers etc. (#23)

* add controller config & wrapper

* add controller setup at app.main

* control loop example

* fix com port

* add agv , ur_arm and raman

* MQTT (3/4): Unified Resources and Sync when starting the server (#28)

* update http upload api

* generate uuid when init device

* example resource json

* fix

* add new example full-content json (device, resource, graph)

* fix full-content json and related reading code

* fix

* add json_schema when initialize resources

* fix

* update schema

* refactor heaterstirrer.dalong

* fix

* fix refactor heaterstirrer.dalong

* refactor syringepump.runze: use ml instead of μL

* Update ilabos/ros/host.py

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: 王俊杰 <1800011822@pku.edu.cn>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Distributed initialization with self-organizing network (#29)

* add distributed launching option "--without_host"

* fix

---------

Co-authored-by: 王俊杰 <1800011822@pku.edu.cn>

* Refactor Workstation: Add resource service and tracking (#30)

* move ilabos/ros/rpc to ilabos/device_comms/rpc, and merge bioyond/aichemeco files under /devices

* add Resource srv and message_converter

* move graphio to ilabos/resources

* refactor resources type conversion

* add resource clients in device_node

* add mock resources service

* pass Gripper1 resource test

* update http resource services

* add AGV compile function

* add AGV transfer protocol

* update full mock_gripper edit_id example

* update full mock_gripper edit_id example

* get and update resource also in protocol_node

* mock resource update in AichemecoHiwo

* Create HT_hiwo.json

* add children in resources

* bugfixes

* fix rpc

* add Revvity winprep

---------

Co-authored-by: wjjxxx <43375851+wjjxxx@users.noreply.github.com>
Co-authored-by: 3218923350 <105201755+3218923350@users.noreply.github.com>

* Distributed launch (2/2): distributed resource create (#32)

* add resource_add request to host for slave mode

* add AGV

* fix protocol resources

* optimize host callbacks

* bugfixes

* add revvity registry

---------

Co-authored-by: 王俊杰 <1800011822@pku.edu.cn>
Co-authored-by: wjjxxx <43375851+wjjxxx@users.noreply.github.com>

* Refactor Driver Files Structure (#33)

* Integration with pywinauto & recorder
Added execute run and initialize procdure

* 酶标仪状态检测、使用示例,整体流程待测试

* nivo ready version

* Add HPLC driver and example script

- Introduced HPLCDriver class for managing HPLC device status and operations.
- Implemented device status monitoring and command execution via ROS2 actions.
- Added example script (hplc.py) demonstrating how to run commands on the HPLC device.
- Created PlayerUtil and UniversalDriver classes for shared functionality across devices.
- Refactored NivoDriver to utilize the new UniversalDriver structure.
- Enhanced error handling and process management in the NivoDriver.

* 修复start的错误定位

* hplc tested ok

* relative path to build msgs

* template_driver & jiageng devices

* fetch correct status type and action type

* fix mtype fetch

* gpc bus integration

* ilab build

* remove chs

* recipe rename

* modbus update 1

* json available

* hplc & modbus rewrite

* Update AgilentHPLC.py

hplc datafile reader

* move ilabos/ros/rpc to ilabos/device_comms/rpc, and merge bioyond/aichemeco files under /devices

* modbus分设备

* gpc

* gpc 2

* fix address

* default register node

* fix MainScreenGPC

* add Resource srv and message_converter

* move graphio to ilabos/resources

* refactor resources type conversion

* add resource clients in device_node

* add mock resources service

* pass Gripper1 resource test

* update http resource services

* add AGV compile function

* add AGV transfer protocol

* update recipe.yaml

* update full mock_gripper edit_id example

* update full mock_gripper edit_id example

* get and update resource also in protocol_node

* mock resource update in AichemecoHiwo

* feat: add other jiageng PLC device code

* ilabos compile

* correct format

* correct recipe format

* correct setup.py format

* remove unnecessary files

* remove unnecessary files

* Create HT_hiwo.json

* add children in resources

* hplc support sample_id

* correct hplc sample_id

* correct hplc sample_id

* hplc upload

* fix type hint

* oss upload tested ver

* recipe yaml fix for linux

* update installation yaml

* refactor: moved all driver files according to its feat

* merge main to dev

---------

Co-authored-by: 王俊杰 <2201110460@stu.pku.edu.cn>
Co-authored-by: Junhan Chang <changjh@pku.edu.cn>
Co-authored-by: jiawei <miaojiawei@dp.tech>

* add: NMR LH and RU device control (#34)

* Add Registry for device drivers and Support GraphML (#35)

* read chemputer graphml

* read graphml in app/main

* add devices in ros/devices

* add schema for devices

* read registry directory and initialize when entry from main

* Delete devices.py

* Update add_protocol.md

* delete unecessary files

* feat: 2278 devices registry yaml (#36)

* read chemputer graphml

* read graphml in app/main

* add devices in ros/devices

* add schema for devices

* read registry directory and initialize when entry from main

* Delete devices.py

* add: NMR LH and RU device control

* fix: modify jiageng devices registry

---------

Co-authored-by: Junhan Chang <changjh@pku.edu.cn>

* Device/Resource Registry and GraphML support (#37)

* add resource type conversion to PLR

* add resource registry and test

* add docs

* fix registry

* add solenoid_valve_mock, its registry and test

* fix registry for directly using examples

* add EvacuateAndRefillProtocol and testcases

* allow function sequence call in ACTION

* add read & write & extra_info for hardware_interface

* Update device_node.py

* add solenoid valve

* add doc developer guide yaml

* fixes for starting IK station

* add graphml grouping parser

* fix graphml grouping parser

* add communication edge parser

* fix io solenoid valve

* Update .gitignore

* Update plates.yaml

---------

Co-authored-by: ColumbiaCC <2100011801@stu.pku.edu.cn>

* Uni-Lab Doc v0.2 (#39)

* add Uni-Lab docs

* change doc name

* Dev (#41)

* Integration with pywinauto & recorder
Added execute run and initialize procdure

* 酶标仪状态检测、使用示例,整体流程待测试

* nivo ready version

* Add HPLC driver and example script

- Introduced HPLCDriver class for managing HPLC device status and operations.
- Implemented device status monitoring and command execution via ROS2 actions.
- Added example script (hplc.py) demonstrating how to run commands on the HPLC device.
- Created PlayerUtil and UniversalDriver classes for shared functionality across devices.
- Refactored NivoDriver to utilize the new UniversalDriver structure.
- Enhanced error handling and process management in the NivoDriver.

* 修复start的错误定位

* hplc tested ok

* relative path to build msgs

* template_driver & jiageng devices

* fetch correct status type and action type

* fix mtype fetch

* gpc bus integration

* ilab build

* remove chs

* recipe rename

* modbus update 1

* json available

* hplc & modbus rewrite

* Update AgilentHPLC.py

hplc datafile reader

* move ilabos/ros/rpc to ilabos/device_comms/rpc, and merge bioyond/aichemeco files under /devices

* modbus分设备

* gpc

* gpc 2

* fix address

* default register node

* fix MainScreenGPC

* add Resource srv and message_converter

* move graphio to ilabos/resources

* refactor resources type conversion

* add resource clients in device_node

* add mock resources service

* pass Gripper1 resource test

* update http resource services

* add AGV compile function

* add AGV transfer protocol

* update recipe.yaml

* update full mock_gripper edit_id example

* update full mock_gripper edit_id example

* get and update resource also in protocol_node

* mock resource update in AichemecoHiwo

* feat: add other jiageng PLC device code

* ilabos compile

* correct format

* correct recipe format

* correct setup.py format

* remove unnecessary files

* remove unnecessary files

* Create HT_hiwo.json

* add children in resources

* hplc support sample_id

* correct hplc sample_id

* correct hplc sample_id

* hplc upload

* fix type hint

* oss upload tested ver

* recipe yaml fix for linux

* update installation yaml

* refactor: moved all driver files according to its feat

* merge main to dev

* add HPLC registry and json

* 升级 ros2-distro-mutex 依赖版本至 0.6

* 修改 ros2-distro-mutex 依赖版本为通配符匹配

* 更新 ros-humble-ilabos-msgs 依赖为 robostack-humble 命名空间

* add resource type conversion to PLR

* add resource registry and test

* feat: 更新oss上传

* fix device id

* add docs

* fix registry

* add solenoid_valve_mock, its registry and test

* fix registry for directly using examples

* add EvacuateAndRefillProtocol and testcases

* allow function sequence call in ACTION

* add read & write & extra_info for hardware_interface

* Update device_node.py

* add solenoid valve

* add doc developer guide yaml

* use robostack-staging

* rclpy version test

* lower rclpy

* ensure 0.6* env

* fixes for starting IK station

* add graphml grouping parser

* fix graphml grouping parser

* add communication edge parser

* fix io solenoid valve

* Update .gitignore

* Update plates.yaml

* Feature/device node later init (#40)

* 修改config路径,方便后续打包
增加device_node打印

* 支持plr序列化/init创建

* 统一命名

* import mgr
logger optimize
banner print

* 日志OK

* fix unicorn frame

* banner print

* correct import format

* file path changes

* 取消后补全,在加载设备的时候直接替换

* converter update

* web page update

* 在线device更新,node继承替换

* 修复动作、状态的类型缺失 和 命令提示

* web功能实现结束

* host节点更改完成
新增status时间戳管理
新增每10s动态发现其他node

* ros2类型的节点也应该被包一次

* 修复类型提示

* websocket 动态显示状态

* add workflow & book theme for docs

* add workflow & book theme for docs

* fix workflow build

* fix workflow build

* 理清启动关系

* stm32 example

* mac . name

* device_instance device_cls

* 新增config添加方式
更新mqtt提示

* plr test

* 移动is_host_mode
新增slave_no_host

* 确保config优先修改生效

* fix graph io

* 支持带参数传入

* 支持物料解析

* 支持物料解析

* device为空的时候不进行绑定或初始化

* protocol node new

* protocol node runnable

* protocol node runnable

---------

Co-authored-by: 王俊杰 <2201110460@stu.pku.edu.cn>
Co-authored-by: Junhan Chang <changjh@pku.edu.cn>
Co-authored-by: jiawei <miaojiawei@dp.tech>
Co-authored-by: ColumbiaCC <2100011801@stu.pku.edu.cn>

* Dev (#45)

* Integration with pywinauto & recorder
Added execute run and initialize procdure

* 酶标仪状态检测、使用示例,整体流程待测试

* nivo ready version

* Add HPLC driver and example script

- Introduced HPLCDriver class for managing HPLC device status and operations.
- Implemented device status monitoring and command execution via ROS2 actions.
- Added example script (hplc.py) demonstrating how to run commands on the HPLC device.
- Created PlayerUtil and UniversalDriver classes for shared functionality across devices.
- Refactored NivoDriver to utilize the new UniversalDriver structure.
- Enhanced error handling and process management in the NivoDriver.

* 修复start的错误定位

* hplc tested ok

* relative path to build msgs

* template_driver & jiageng devices

* fetch correct status type and action type

* fix mtype fetch

* gpc bus integration

* ilab build

* remove chs

* recipe rename

* modbus update 1

* json available

* hplc & modbus rewrite

* Update AgilentHPLC.py

hplc datafile reader

* move ilabos/ros/rpc to ilabos/device_comms/rpc, and merge bioyond/aichemeco files under /devices

* modbus分设备

* gpc

* gpc 2

* fix address

* default register node

* fix MainScreenGPC

* add Resource srv and message_converter

* move graphio to ilabos/resources

* refactor resources type conversion

* add resource clients in device_node

* add mock resources service

* pass Gripper1 resource test

* update http resource services

* add AGV compile function

* add AGV transfer protocol

* update recipe.yaml

* update full mock_gripper edit_id example

* update full mock_gripper edit_id example

* get and update resource also in protocol_node

* mock resource update in AichemecoHiwo

* feat: add other jiageng PLC device code

* ilabos compile

* correct format

* correct recipe format

* correct setup.py format

* remove unnecessary files

* remove unnecessary files

* Create HT_hiwo.json

* add children in resources

* hplc support sample_id

* correct hplc sample_id

* correct hplc sample_id

* hplc upload

* fix type hint

* oss upload tested ver

* recipe yaml fix for linux

* update installation yaml

* refactor: moved all driver files according to its feat

* merge main to dev

* add HPLC registry and json

* 升级 ros2-distro-mutex 依赖版本至 0.6

* 修改 ros2-distro-mutex 依赖版本为通配符匹配

* 更新 ros-humble-ilabos-msgs 依赖为 robostack-humble 命名空间

* add resource type conversion to PLR

* add resource registry and test

* feat: 更新oss上传

* fix device id

* add docs

* fix registry

* add solenoid_valve_mock, its registry and test

* fix registry for directly using examples

* add EvacuateAndRefillProtocol and testcases

* allow function sequence call in ACTION

* add read & write & extra_info for hardware_interface

* Update device_node.py

* add solenoid valve

* add doc developer guide yaml

* use robostack-staging

* rclpy version test

* lower rclpy

* ensure 0.6* env

* fixes for starting IK station

* add graphml grouping parser

* fix graphml grouping parser

* add communication edge parser

* fix io solenoid valve

* Update .gitignore

* Update plates.yaml

* Feature/device node later init (#40)

* 修改config路径,方便后续打包
增加device_node打印

* 支持plr序列化/init创建

* 统一命名

* import mgr
logger optimize
banner print

* 日志OK

* fix unicorn frame

* banner print

* correct import format

* file path changes

* 取消后补全,在加载设备的时候直接替换

* converter update

* web page update

* 在线device更新,node继承替换

* 修复动作、状态的类型缺失 和 命令提示

* web功能实现结束

* host节点更改完成
新增status时间戳管理
新增每10s动态发现其他node

* ros2类型的节点也应该被包一次

* 修复类型提示

* websocket 动态显示状态

* add workflow & book theme for docs

* add workflow & book theme for docs

* fix workflow build

* fix workflow build

* 理清启动关系

* stm32 example

* mac . name

* device_instance device_cls

* 新增config添加方式
更新mqtt提示

* plr test

* 移动is_host_mode
新增slave_no_host

* 确保config优先修改生效

* fix graph io

* 支持带参数传入

* 支持物料解析

* 支持物料解析

* device为空的时候不进行绑定或初始化

* protocol node new

* protocol node runnable

* protocol node runnable

* Feature/device node later init (#42)

* 修改config路径,方便后续打包
增加device_node打印

* 支持plr序列化/init创建

* 统一命名

* import mgr
logger optimize
banner print

* 日志OK

* fix unicorn frame

* banner print

* correct import format

* file path changes

* 取消后补全,在加载设备的时候直接替换

* converter update

* web page update

* 在线device更新,node继承替换

* 修复动作、状态的类型缺失 和 命令提示

* web功能实现结束

* host节点更改完成
新增status时间戳管理
新增每10s动态发现其他node

* ros2类型的节点也应该被包一次

* 修复类型提示

* websocket 动态显示状态

* add workflow & book theme for docs

* add workflow & book theme for docs

* fix workflow build

* fix workflow build

* 理清启动关系

* stm32 example

* mac . name

* device_instance device_cls

* 新增config添加方式
更新mqtt提示

* plr test

* 移动is_host_mode
新增slave_no_host

* 确保config优先修改生效

* fix graph io

* 支持带参数传入

* 支持物料解析

* 支持物料解析

* device为空的时候不进行绑定或初始化

* protocol node new

* protocol node runnable

* protocol node runnable

* action

* plr suc

* plr suc!!

* plr suc!!

* plr suc!!

* plr msgs

* Feature/device node later init (#43)

* 修改config路径,方便后续打包
增加device_node打印

* 支持plr序列化/init创建

* 统一命名

* import mgr
logger optimize
banner print

* 日志OK

* fix unicorn frame

* banner print

* correct import format

* file path changes

* 取消后补全,在加载设备的时候直接替换

* converter update

* web page update

* 在线device更新,node继承替换

* 修复动作、状态的类型缺失 和 命令提示

* web功能实现结束

* host节点更改完成
新增status时间戳管理
新增每10s动态发现其他node

* ros2类型的节点也应该被包一次

* 修复类型提示

* websocket 动态显示状态

* add workflow & book theme for docs

* add workflow & book theme for docs

* fix workflow build

* fix workflow build

* 理清启动关系

* stm32 example

* mac . name

* device_instance device_cls

* 新增config添加方式
更新mqtt提示

* plr test

* 移动is_host_mode
新增slave_no_host

* 确保config优先修改生效

* fix graph io

* 支持带参数传入

* 支持物料解析

* 支持物料解析

* device为空的时候不进行绑定或初始化

* protocol node new

* protocol node runnable

* protocol node runnable

* action

* plr suc

* plr suc!!

* plr suc!!

* plr suc!!

* plr msgs

* plr

* action

* plr reg fix

* Feature/device node later init (#44)

* 修改config路径,方便后续打包
增加device_node打印

* 支持plr序列化/init创建

* 统一命名

* import mgr
logger optimize
banner print

* 日志OK

* fix unicorn frame

* banner print

* correct import format

* file path changes

* 取消后补全,在加载设备的时候直接替换

* converter update

* web page update

* 在线device更新,node继承替换

* 修复动作、状态的类型缺失 和 命令提示

* web功能实现结束

* host节点更改完成
新增status时间戳管理
新增每10s动态发现其他node

* ros2类型的节点也应该被包一次

* 修复类型提示

* websocket 动态显示状态

* add workflow & book theme for docs

* add workflow & book theme for docs

* fix workflow build

* fix workflow build

* 理清启动关系

* stm32 example

* mac . name

* device_instance device_cls

* 新增config添加方式
更新mqtt提示

* plr test

* 移动is_host_mode
新增slave_no_host

* 确保config优先修改生效

* fix graph io

* 支持带参数传入

* 支持物料解析

* 支持物料解析

* device为空的时候不进行绑定或初始化

* protocol node new

* protocol node runnable

* protocol node runnable

* action

* plr suc

* plr suc!!

* plr suc!!

* plr suc!!

* plr msgs

* plr

* fix convert error
fix async logic error
added async error print

* new device test

* test resource add

* test resource add

* test resource add

* test resource add

* local env setup

* node type fix
temp fix root_node error
fix convert res from type error

* resource tracker

* fix bug from qhh

* fix bug from qhh

* fix bug from qhh

* fix bug from qhh

* refactor MQTT client logging and connection handling; update group ID in config

* driver_params allow empty

* allow other init param

* fix driver param and enhance type hint

* refactor MQConfig to use double quotes for string literals

* fix wrong function calling

* fix wrong function calling

* fix log for mac

* fix networkx compatibility

* add mqtt loggers

* add action to jsonschema converter

* random client id

* type converter & registry

* correct conversion

* fix action publish only from discovered devices

* add "Bio" tag for action doc generation

* 改进module提示

* Fix doc

* mqtt不连接也可用
性价样例提示

* add docs

* 更新plr test案例

* Update intro.md

* 更新有机案例

* skip

---------

Co-authored-by: Harvey Que <Q-Query@outlook.com>
Co-authored-by: Junhan Chang <1700011741@pku.edu.cn>

---------

Co-authored-by: 王俊杰 <2201110460@stu.pku.edu.cn>
Co-authored-by: Junhan Chang <changjh@pku.edu.cn>
Co-authored-by: jiawei <miaojiawei@dp.tech>
Co-authored-by: ColumbiaCC <2100011801@stu.pku.edu.cn>
Co-authored-by: Harvey Que <Q-Query@outlook.com>
Co-authored-by: Junhan Chang <1700011741@pku.edu.cn>

* Canonicalize before Open Source (#46)

* big big refactor try01

* refactor 02

---------

Co-authored-by: ck <xiaoyeqiannian@163.com>
Co-authored-by: 王俊杰 <1800011822@pku.edu.cn>
Co-authored-by: q434343 <554662886@qq.com>
Co-authored-by: Xuwznln <xuwznln@gmail.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: wjjxxx <43375851+wjjxxx@users.noreply.github.com>
Co-authored-by: 3218923350 <105201755+3218923350@users.noreply.github.com>
Co-authored-by: Xuwznln <1023025701@qq.com>
Co-authored-by: 王俊杰 <2201110460@stu.pku.edu.cn>
Co-authored-by: jiawei <miaojiawei@dp.tech>
Co-authored-by: Jiawei <91898272+jiawei723@users.noreply.github.com>
Co-authored-by: ColumbiaCC <2100011801@stu.pku.edu.cn>
Co-authored-by: Harvey Que <Q-Query@outlook.com>
2025-04-17 15:09:58 +08:00

229 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from abc import abstractmethod
from functools import wraps
import inspect
import json
import logging
import queue
from socket import socket
import threading
import time
import traceback
from typing import Optional
import serial
class SingleRunningExecutor(object):
"""
异步执行单个任务不允许重复执行通过class的函数获得唯一任务名的实例
需要对
"""
__instance = {}
@classmethod
def get_instance(cls, func, post_func=None, name=None, *var, **kwargs):
print(f"!!!get_instance: {name} {kwargs}")
if name is None:
name = func.__name__
if name not in cls.__instance:
cls.__instance[name] = cls(func, post_func, *var, **kwargs)
return cls.__instance[name]
start_time: float = None
end_time: float = None
is_running: bool = None
is_error: bool = None
is_success: bool = None
@property
def is_ended(self):
return not self.is_running and (self.is_error or self.is_success)
@property
def is_started(self):
return self.is_running or self.is_error or self.is_success
def reset(self):
self.start_time = None
self.end_time = None
self.is_running = False
self.is_error = False
self.is_success = False
self._final_var = {}
self._thread = threading.Thread(target=self._execute)
def __init__(self, func, post_func=None, *var, **kwargs):
self._func = func
self._post_func = post_func
self._sig = inspect.signature(self._func)
self._var = var
self._kwargs = kwargs
self.reset()
def _execute(self):
res = None
try:
for ind, i in enumerate(self._var):
self._final_var[list(self._sig.parameters.keys())[ind]] = i
for k, v in self._kwargs.items():
if k in self._sig.parameters.keys():
self._final_var[k] = v
self.is_running = True
print(f"!!!_final_var: {self._final_var}")
res = self._func(**self._final_var)
except Exception as e:
self.is_running = False
self.is_error = True
traceback.print_exc()
if callable(self._post_func):
self._post_func(res, self._final_var)
def start(self, **kwargs):
if len(kwargs) > 0:
self._kwargs = kwargs
self.start_time = time.time()
self._thread.start()
def join(self):
if self.is_running:
self._thread.join()
self.end_time = time.time()
def command(func):
"""
Decorator for command_set execution. Checks if the method is called in the same thread as the class instance,
if so enqueues the command_set and waits for a reply in the reply queue. Else it concludes it must be the command
handler thread and actually executes the method. This way methods in the child classes need to be written
just once and decorated accordingly.
:return: decorated method
"""
@wraps(func)
def wrapper(*args, **kwargs):
device_instance = args[0]
if threading.get_ident() == device_instance.current_thread:
command_set = [func, args, kwargs]
device_instance.command_queue.put(command_set)
while True:
if not device_instance.reply_queue.empty():
return device_instance.reply_queue.get()
else:
return func(*args, **kwargs)
return wrapper
class UniversalDriver(object):
def _init_logger(self):
self.logger = logging.getLogger(f"{self.__class__.__name__}_logger")
def __init__(self):
self._init_logger()
def execute_command_from_outer(self, command: str):
try:
command = json.loads(command.replace("'", '"').replace("False", "false").replace("True", "true")) # 要求不能出现'作为字符串
except Exception as e:
print(f"Json解析失败: {e}")
return False
for k, v in command.items():
print(f"执行{k}方法,参数为{v}")
try:
getattr(self, k)(**v)
except Exception as e:
print(f"执行{k}方法失败: {e}")
traceback.print_exc()
return False
return True
class TransportDriver(UniversalDriver):
COMMAND_QUEUE_ENABLE = True
command_handler_thread: Optional[threading.Thread] = None
__connection: Optional[serial.Serial | socket] = None
def _init_command_queue(self):
self.command_queue = queue.Queue()
self.reply_queue = queue.Queue()
def __command_handler_daemon(self):
while True:
try:
if not self.command_queue.empty():
command_item = self.command_queue.get()
method = command_item[0]
arguments = command_item[1]
keywordarguments = command_item[2]
reply = method(*arguments, **keywordarguments)
self.reply_queue.put(reply)
else:
self.keepalive()
except ValueError as e:
# workaround if something goes wrong with the serial connection
# future me will certainly not hate past me for this...
self.logger.critical(e)
self.__connection.flush()
# thread-safe purging of both queues
while not self.command_queue.empty():
self.command_queue.get()
while not self.reply_queue.empty():
self.reply_queue.get()
def launch_command_handler(self):
if self.COMMAND_QUEUE_ENABLE:
self.command_handler_thread = threading.Thread(target=self.__command_handler_daemon, name="{0}_command_handler".format(self.device_name), daemon=True)
self.command_handler_thread.start()
@abstractmethod
def open_connection(self):
pass
@abstractmethod
def close_connection(self):
pass
@abstractmethod
def keepalive(self):
pass
def __init__(self):
super().__init__()
if self.COMMAND_QUEUE_ENABLE:
self.launch_command_handler()
class DriverChecker(object):
def __init__(self, driver, interval: int | float):
self.driver = driver
self.interval = interval
self._thread = threading.Thread(target=self._monitor)
self._thread.daemon = True
self._stop_event = threading.Event()
def _monitor(self):
while not self._stop_event.is_set():
try:
# print(self.__class__.__name__, "Started!")
self.check()
except Exception as e:
print(f"Error in {self.__class__.__name__}: {str(e)}")
traceback.print_exc()
finally:
time.sleep(self.interval)
@abstractmethod
def check(self):
"""子类必须实现此方法"""
raise NotImplementedError
def start_monitoring(self):
self._thread.start()
def stop_monitoring(self):
self._stop_event.set()
self._thread.join()