reachy-mini 1.2.5rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reachy_mini/__init__.py +4 -0
- reachy_mini/apps/__init__.py +25 -0
- reachy_mini/apps/app.py +258 -0
- reachy_mini/apps/assistant.py +787 -0
- reachy_mini/apps/manager.py +312 -0
- reachy_mini/apps/sources/__init__.py +4 -0
- reachy_mini/apps/sources/hf_space.py +106 -0
- reachy_mini/apps/sources/local_common_venv.py +567 -0
- reachy_mini/apps/templates/README.md.j2 +12 -0
- reachy_mini/apps/templates/gitignore.j2 +3 -0
- reachy_mini/apps/templates/index.html.j2 +40 -0
- reachy_mini/apps/templates/main.py.j2 +74 -0
- reachy_mini/apps/templates/pyproject.toml.j2 +28 -0
- reachy_mini/apps/templates/static/index.html.j2 +27 -0
- reachy_mini/apps/templates/static/main.js.j2 +47 -0
- reachy_mini/apps/templates/static/style.css.j2 +25 -0
- reachy_mini/apps/templates/style.css.j2 +411 -0
- reachy_mini/apps/utils.py +30 -0
- reachy_mini/assets/config/hardware_config.yaml +164 -0
- reachy_mini/assets/confused1.wav +0 -0
- reachy_mini/assets/count.wav +0 -0
- reachy_mini/assets/dance1.wav +0 -0
- reachy_mini/assets/firmware/CHANGELOG.md +15 -0
- reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.2.bin +0 -0
- reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin +0 -0
- reachy_mini/assets/firmware/update.sh +9 -0
- reachy_mini/assets/go_sleep.wav +0 -0
- reachy_mini/assets/impatient1.wav +0 -0
- reachy_mini/assets/kinematics_data.json +253 -0
- reachy_mini/assets/models/fknetwork.dynamic.onnx +0 -0
- reachy_mini/assets/models/fknetwork.onnx +0 -0
- reachy_mini/assets/models/fknetwork_int8.onnx +0 -0
- reachy_mini/assets/models/iknetwork.onnx +0 -0
- reachy_mini/assets/wake_up.wav +0 -0
- reachy_mini/daemon/__init__.py +1 -0
- reachy_mini/daemon/app/__init__.py +1 -0
- reachy_mini/daemon/app/bg_job_register.py +142 -0
- reachy_mini/daemon/app/dashboard/static/assets/KO-cartoon-static.svg +40 -0
- reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon-static.svg +42 -0
- reachy_mini/daemon/app/dashboard/static/assets/awake-cartoon.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/go-to-sleep-cartoon.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon-static.svg +50 -0
- reachy_mini/daemon/app/dashboard/static/assets/no-wifi-cartoon.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-awake.svg +18 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-connection-lost-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-go-to-sleep-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-ko.svg +22 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping-static.svg +41 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-sleeping.svg +18 -0
- reachy_mini/daemon/app/dashboard/static/assets/reachy-mini-wake-up-animation.svg +6 -0
- reachy_mini/daemon/app/dashboard/static/css/app.css +1433 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Archivo-Italic-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Archivo-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Asap-Italic-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/fonts/Asap-VariableFont_wdth,wght.ttf +0 -0
- reachy_mini/daemon/app/dashboard/static/js/3rdparty/gstwebrtc-api-2.0.0.min.js +5 -0
- reachy_mini/daemon/app/dashboard/static/js/apps.js +323 -0
- reachy_mini/daemon/app/dashboard/static/js/appstore.js +167 -0
- reachy_mini/daemon/app/dashboard/static/js/daemon.js +169 -0
- reachy_mini/daemon/app/dashboard/static/js/health_check.js +9 -0
- reachy_mini/daemon/app/dashboard/static/js/move_player.js +132 -0
- reachy_mini/daemon/app/dashboard/static/js/notification.js +41 -0
- reachy_mini/daemon/app/dashboard/static/js/update.js +132 -0
- reachy_mini/daemon/app/dashboard/static/js/volume_control.js +252 -0
- reachy_mini/daemon/app/dashboard/static/js/wifi.js +176 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/README.md +15 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/package-lock.json +1127 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/package.json +6 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/pnpm-lock.yaml +608 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/postcss.config.js +6 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/styles/app.css +185 -0
- reachy_mini/daemon/app/dashboard/tailwindcss/tailwind.config.js +11 -0
- reachy_mini/daemon/app/dashboard/templates/base.html +21 -0
- reachy_mini/daemon/app/dashboard/templates/index.html +20 -0
- reachy_mini/daemon/app/dashboard/templates/sections/apps.html +8 -0
- reachy_mini/daemon/app/dashboard/templates/sections/appstore.html +35 -0
- reachy_mini/daemon/app/dashboard/templates/sections/daemon.html +45 -0
- reachy_mini/daemon/app/dashboard/templates/sections/move_player.html +121 -0
- reachy_mini/daemon/app/dashboard/templates/sections/notification.html +19 -0
- reachy_mini/daemon/app/dashboard/templates/sections/update.html +54 -0
- reachy_mini/daemon/app/dashboard/templates/sections/wifi.html +46 -0
- reachy_mini/daemon/app/dashboard/templates/settings.html +14 -0
- reachy_mini/daemon/app/dependencies.py +41 -0
- reachy_mini/daemon/app/main.py +469 -0
- reachy_mini/daemon/app/models.py +149 -0
- reachy_mini/daemon/app/routers/apps.py +114 -0
- reachy_mini/daemon/app/routers/daemon.py +85 -0
- reachy_mini/daemon/app/routers/kinematics.py +57 -0
- reachy_mini/daemon/app/routers/motors.py +41 -0
- reachy_mini/daemon/app/routers/move.py +265 -0
- reachy_mini/daemon/app/routers/state.py +146 -0
- reachy_mini/daemon/app/routers/update.py +86 -0
- reachy_mini/daemon/app/routers/volume.py +423 -0
- reachy_mini/daemon/app/routers/wifi_config.py +219 -0
- reachy_mini/daemon/app/services/__init__.py +1 -0
- reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py +796 -0
- reachy_mini/daemon/app/services/bluetooth/commands/HOTSPOT.sh +7 -0
- reachy_mini/daemon/app/services/bluetooth/commands/RESTART_DAEMON.sh +4 -0
- reachy_mini/daemon/app/services/bluetooth/commands/SOFTWARE_RESET.sh +7 -0
- reachy_mini/daemon/app/services/bluetooth/install_service_bluetooth.sh +39 -0
- reachy_mini/daemon/app/services/gpio_shutdown/__init__.py +1 -0
- reachy_mini/daemon/app/services/gpio_shutdown/install_service.sh +33 -0
- reachy_mini/daemon/app/services/gpio_shutdown/launcher.sh +3 -0
- reachy_mini/daemon/app/services/gpio_shutdown/shutdown_monitor.py +28 -0
- reachy_mini/daemon/app/services/wireless/generate_asoundrc.sh +70 -0
- reachy_mini/daemon/app/services/wireless/install_service.sh +33 -0
- reachy_mini/daemon/app/services/wireless/launcher.sh +5 -0
- reachy_mini/daemon/backend/__init__.py +1 -0
- reachy_mini/daemon/backend/abstract.py +815 -0
- reachy_mini/daemon/backend/mujoco/__init__.py +36 -0
- reachy_mini/daemon/backend/mujoco/backend.py +395 -0
- reachy_mini/daemon/backend/mujoco/utils.py +59 -0
- reachy_mini/daemon/backend/mujoco/video_udp.py +57 -0
- reachy_mini/daemon/backend/robot/__init__.py +8 -0
- reachy_mini/daemon/backend/robot/backend.py +597 -0
- reachy_mini/daemon/daemon.py +651 -0
- reachy_mini/daemon/utils.py +116 -0
- reachy_mini/descriptions/reachy_mini/mjcf/additional.xml +6 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/5w_speaker.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_body_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_l_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_holder_r_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/antenna_interface_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/arducam.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/b3b_eh_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bearing_85x110x13.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/big_lens_d40.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_down_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_foot_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_top_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/body_turning_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/bts2_m2_6x8.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/README.m +1 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/coarse/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/collision/fine/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/croissant_1k.obj +5021 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/croissant_1k.blend/textures/croissant_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_b_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_f_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_case_m_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_horn_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/dc15_a01_led_cap2_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/food_apple_01_1k.obj +18045 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/food_apple_01_1k.blend/textures/food_apple_01_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/glasses_dolder_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_back_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_front_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/head_mic_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d30_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/lens_cap_d40_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/m12_fisheye_lens_1_8mm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/mp01062_stewart_arm_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/neck_reference_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/phs_1_7x20_5_dc10_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/pp01102_arducam_carter.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/rubber_duck_toy_1k.obj +8940 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/rubber_duck_toy_1k.blend/textures/rubber_duck_toy_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/small_lens_d30.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_ball__2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_link_rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_main_plate_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/stewart_tricap_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/textures/wooden_table_02_diff_1k.png +0 -0
- reachy_mini/descriptions/reachy_mini/mjcf/assets/wooden_table_02_1k.blend/wooden_table_02_1k.obj +485 -0
- reachy_mini/descriptions/reachy_mini/mjcf/config.json +21 -0
- reachy_mini/descriptions/reachy_mini/mjcf/joints_properties.xml +29 -0
- reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml +642 -0
- reachy_mini/descriptions/reachy_mini/mjcf/reachy_mini.xml.bak +442 -0
- reachy_mini/descriptions/reachy_mini/mjcf/scene.xml +24 -0
- reachy_mini/descriptions/reachy_mini/mjcf/scenes/empty.xml +27 -0
- reachy_mini/descriptions/reachy_mini/mjcf/scenes/minimal.xml +132 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/5w_speaker.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_body_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_l_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_holder_r_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/antenna_interface_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arducam.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arm.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/arm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/b3b_eh_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/ball.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/ball.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bearing_85x110x13.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/big_lens_d40.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_down_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_foot_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_top_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/body_turning_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bottom_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/bts2_m2_6x8.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/README.m +1 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/coarse/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_back_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/body_top_3dprint_collider_front_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/collision/fine/head_one_3dprint_collider_0.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_b_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_f_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_case_m_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_horn_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/dc15_a01_led_cap2_dummy.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/drive_palonier__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/eye_support.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/foot.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/foot.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/glasses_dolder_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_back_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_front_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_head_back.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_interface.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_mic_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/head_shell_front.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d30_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/lens_cap_d40_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_fisheye_lens_1_8mm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/m12_lens.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/main_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mid_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/mp01062_stewart_arm_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/neck_reference_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_1.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/phs_1_7x20_5_dc10_3.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/plateform.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp00xxx_stewart_rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01062_stewart_arm.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01063_stewart_plateform.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01064_stewart_main_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01065_stewart_side_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01066_stewart_mid_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01067_bottom_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01068_top_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01069_head_shell_front.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01070_head_head_back.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01071_turning_bowl.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01072_turning_end.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01078_glasses.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01079_back_big_eye.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01080_back_small_eye.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/pp01102_arducam_carter.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/shape.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/shape.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/side_plate.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/small_lens_d30.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_ball__2.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_link_rod.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_main_plate_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/stewart_tricap_3dprint.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/test_antenna_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/top_body.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/turning_bowl.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.part +13 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/uc_a37_rev_a_step.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0122topcabinetcase_95__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0123middlecase_56__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_default.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.part +14 -0
- reachy_mini/descriptions/reachy_mini/urdf/assets/wj_wk00_0124bottomcase_45__configuration_simple_axe.stl +0 -0
- reachy_mini/descriptions/reachy_mini/urdf/config.json +18 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot.urdf +3281 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot.urdf.bak +3282 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot_no_collision.urdf +2316 -0
- reachy_mini/descriptions/reachy_mini/urdf/robot_simple_collision.urdf +2399 -0
- reachy_mini/io/__init__.py +15 -0
- reachy_mini/io/abstract.py +70 -0
- reachy_mini/io/audio_ws.py +242 -0
- reachy_mini/io/protocol.py +44 -0
- reachy_mini/io/video_ws.py +135 -0
- reachy_mini/io/ws_controller.py +120 -0
- reachy_mini/io/zenoh_client.py +273 -0
- reachy_mini/io/zenoh_server.py +230 -0
- reachy_mini/kinematics/__init__.py +68 -0
- reachy_mini/kinematics/analytical_kinematics.py +151 -0
- reachy_mini/kinematics/nn_kinematics.py +109 -0
- reachy_mini/kinematics/placo_kinematics.py +656 -0
- reachy_mini/media/__init__.py +1 -0
- reachy_mini/media/audio_base.py +111 -0
- reachy_mini/media/audio_control_utils.py +455 -0
- reachy_mini/media/audio_gstreamer.py +272 -0
- reachy_mini/media/audio_sounddevice.py +321 -0
- reachy_mini/media/audio_utils.py +114 -0
- reachy_mini/media/camera_base.py +100 -0
- reachy_mini/media/camera_constants.py +152 -0
- reachy_mini/media/camera_gstreamer.py +231 -0
- reachy_mini/media/camera_opencv.py +89 -0
- reachy_mini/media/camera_utils.py +111 -0
- reachy_mini/media/media_manager.py +281 -0
- reachy_mini/media/webrtc_client_gstreamer.py +288 -0
- reachy_mini/media/webrtc_daemon.py +334 -0
- reachy_mini/motion/__init__.py +4 -0
- reachy_mini/motion/goto.py +71 -0
- reachy_mini/motion/move.py +43 -0
- reachy_mini/motion/recorded_move.py +146 -0
- reachy_mini/reachy_mini.py +753 -0
- reachy_mini/tools/reflash_motors.py +116 -0
- reachy_mini/tools/setup_motor.py +422 -0
- reachy_mini/tools/setup_motor_rpi.py +108 -0
- reachy_mini/utils/__init__.py +46 -0
- reachy_mini/utils/constants.py +9 -0
- reachy_mini/utils/hardware_config/__init__.py +1 -0
- reachy_mini/utils/hardware_config/parser.py +65 -0
- reachy_mini/utils/interpolation.py +227 -0
- reachy_mini/utils/parse_urdf_for_kinematics.py +110 -0
- reachy_mini/utils/rerun.py +320 -0
- reachy_mini/utils/wireless_version/__init__.py +1 -0
- reachy_mini/utils/wireless_version/startup_check.py +144 -0
- reachy_mini/utils/wireless_version/update.py +20 -0
- reachy_mini/utils/wireless_version/update_available.py +61 -0
- reachy_mini/utils/wireless_version/utils.py +39 -0
- reachy_mini-1.2.5rc1.dist-info/METADATA +161 -0
- reachy_mini-1.2.5rc1.dist-info/RECORD +479 -0
- reachy_mini-1.2.5rc1.dist-info/WHEEL +5 -0
- reachy_mini-1.2.5rc1.dist-info/entry_points.txt +4 -0
- reachy_mini-1.2.5rc1.dist-info/licenses/LICENSE +201 -0
- reachy_mini-1.2.5rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""State-related API routes.
|
|
2
|
+
|
|
3
|
+
This exposes:
|
|
4
|
+
- basic get routes to retrieve most common fields
|
|
5
|
+
- full state and streaming state updates
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from datetime import datetime, timezone
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from fastapi import APIRouter, Depends, WebSocket, WebSocketDisconnect
|
|
13
|
+
|
|
14
|
+
from ....daemon.backend.abstract import Backend
|
|
15
|
+
from ..dependencies import get_backend, ws_get_backend
|
|
16
|
+
from ..models import AnyPose, FullState, as_any_pose
|
|
17
|
+
|
|
18
|
+
router = APIRouter(prefix="/state")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@router.get("/present_head_pose")
|
|
22
|
+
async def get_head_pose(
|
|
23
|
+
use_pose_matrix: bool = False,
|
|
24
|
+
backend: Backend = Depends(get_backend),
|
|
25
|
+
) -> AnyPose:
|
|
26
|
+
"""Get the present head pose.
|
|
27
|
+
|
|
28
|
+
Arguments:
|
|
29
|
+
use_pose_matrix (bool): Whether to use the pose matrix representation (4x4 flattened) or the translation + Euler angles representation (x, y, z, roll, pitch, yaw).
|
|
30
|
+
backend (Backend): The backend instance.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
AnyPose: The present head pose.
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
return as_any_pose(backend.get_present_head_pose(), use_pose_matrix)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@router.get("/present_body_yaw")
|
|
40
|
+
async def get_body_yaw(
|
|
41
|
+
backend: Backend = Depends(get_backend),
|
|
42
|
+
) -> float:
|
|
43
|
+
"""Get the present body yaw (in radians)."""
|
|
44
|
+
return backend.get_present_body_yaw()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@router.get("/present_antenna_joint_positions")
|
|
48
|
+
async def get_antenna_joint_positions(
|
|
49
|
+
backend: Backend = Depends(get_backend),
|
|
50
|
+
) -> tuple[float, float]:
|
|
51
|
+
"""Get the present antenna joint positions (in radians) - (left, right)."""
|
|
52
|
+
pos = backend.get_present_antenna_joint_positions()
|
|
53
|
+
assert len(pos) == 2
|
|
54
|
+
return (pos[0], pos[1])
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@router.get("/full")
|
|
58
|
+
async def get_full_state(
|
|
59
|
+
with_control_mode: bool = True,
|
|
60
|
+
with_head_pose: bool = True,
|
|
61
|
+
with_target_head_pose: bool = False,
|
|
62
|
+
with_head_joints: bool = False,
|
|
63
|
+
with_target_head_joints: bool = False,
|
|
64
|
+
with_body_yaw: bool = True,
|
|
65
|
+
with_target_body_yaw: bool = False,
|
|
66
|
+
with_antenna_positions: bool = True,
|
|
67
|
+
with_target_antenna_positions: bool = False,
|
|
68
|
+
with_passive_joints: bool = False,
|
|
69
|
+
use_pose_matrix: bool = False,
|
|
70
|
+
backend: Backend = Depends(get_backend),
|
|
71
|
+
) -> FullState:
|
|
72
|
+
"""Get the full robot state, with optional fields."""
|
|
73
|
+
result: dict[str, Any] = {}
|
|
74
|
+
|
|
75
|
+
if with_control_mode:
|
|
76
|
+
result["control_mode"] = backend.get_motor_control_mode().value
|
|
77
|
+
|
|
78
|
+
if with_head_pose:
|
|
79
|
+
pose = backend.get_present_head_pose()
|
|
80
|
+
result["head_pose"] = as_any_pose(pose, use_pose_matrix)
|
|
81
|
+
if with_target_head_pose:
|
|
82
|
+
target_pose = backend.target_head_pose
|
|
83
|
+
assert target_pose is not None
|
|
84
|
+
result["target_head_pose"] = as_any_pose(target_pose, use_pose_matrix)
|
|
85
|
+
if with_head_joints:
|
|
86
|
+
result["head_joints"] = backend.get_present_head_joint_positions()
|
|
87
|
+
if with_target_head_joints:
|
|
88
|
+
result["target_head_joints"] = backend.target_head_joint_positions
|
|
89
|
+
if with_body_yaw:
|
|
90
|
+
result["body_yaw"] = backend.get_present_body_yaw()
|
|
91
|
+
if with_target_body_yaw:
|
|
92
|
+
result["target_body_yaw"] = backend.target_body_yaw
|
|
93
|
+
if with_antenna_positions:
|
|
94
|
+
result["antennas_position"] = backend.get_present_antenna_joint_positions()
|
|
95
|
+
if with_target_antenna_positions:
|
|
96
|
+
result["target_antennas_position"] = backend.target_antenna_joint_positions
|
|
97
|
+
if with_passive_joints:
|
|
98
|
+
joints = backend.get_present_passive_joint_positions()
|
|
99
|
+
if joints is not None:
|
|
100
|
+
result["passive_joints"] = list(joints.values())
|
|
101
|
+
else:
|
|
102
|
+
result["passive_joints"] = None
|
|
103
|
+
|
|
104
|
+
result["timestamp"] = datetime.now(timezone.utc)
|
|
105
|
+
return FullState.model_validate(result)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@router.websocket("/ws/full")
|
|
109
|
+
async def ws_full_state(
|
|
110
|
+
websocket: WebSocket,
|
|
111
|
+
frequency: float = 10.0,
|
|
112
|
+
with_head_pose: bool = True,
|
|
113
|
+
with_target_head_pose: bool = False,
|
|
114
|
+
with_head_joints: bool = False,
|
|
115
|
+
with_target_head_joints: bool = False,
|
|
116
|
+
with_body_yaw: bool = True,
|
|
117
|
+
with_target_body_yaw: bool = False,
|
|
118
|
+
with_antenna_positions: bool = True,
|
|
119
|
+
with_target_antenna_positions: bool = False,
|
|
120
|
+
with_passive_joints: bool = False,
|
|
121
|
+
use_pose_matrix: bool = False,
|
|
122
|
+
backend: Backend = Depends(ws_get_backend),
|
|
123
|
+
) -> None:
|
|
124
|
+
"""WebSocket endpoint to stream the full state of the robot."""
|
|
125
|
+
await websocket.accept()
|
|
126
|
+
period = 1.0 / frequency
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
while True:
|
|
130
|
+
full_state = await get_full_state(
|
|
131
|
+
with_head_pose=with_head_pose,
|
|
132
|
+
with_target_head_pose=with_target_head_pose,
|
|
133
|
+
with_head_joints=with_head_joints,
|
|
134
|
+
with_target_head_joints=with_target_head_joints,
|
|
135
|
+
with_body_yaw=with_body_yaw,
|
|
136
|
+
with_target_body_yaw=with_target_body_yaw,
|
|
137
|
+
with_antenna_positions=with_antenna_positions,
|
|
138
|
+
with_target_antenna_positions=with_target_antenna_positions,
|
|
139
|
+
with_passive_joints=with_passive_joints,
|
|
140
|
+
use_pose_matrix=use_pose_matrix,
|
|
141
|
+
backend=backend,
|
|
142
|
+
)
|
|
143
|
+
await websocket.send_text(full_state.model_dump_json())
|
|
144
|
+
await asyncio.sleep(period)
|
|
145
|
+
except WebSocketDisconnect:
|
|
146
|
+
pass
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Update router for Reachy Mini Daemon API.
|
|
2
|
+
|
|
3
|
+
This module provides endpoints to check for updates, start updates, and monitor update status.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import threading
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from fastapi import APIRouter, HTTPException, WebSocket
|
|
11
|
+
|
|
12
|
+
from reachy_mini.daemon.app import bg_job_register
|
|
13
|
+
from reachy_mini.daemon.app.bg_job_register import JobInfo
|
|
14
|
+
from reachy_mini.utils.wireless_version.update import update_reachy_mini
|
|
15
|
+
from reachy_mini.utils.wireless_version.update_available import (
|
|
16
|
+
get_local_version,
|
|
17
|
+
get_pypi_version,
|
|
18
|
+
is_update_available,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
router = APIRouter(prefix="/update")
|
|
22
|
+
busy_lock = threading.Lock()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@router.get("/available")
|
|
26
|
+
def available(pre_release: bool = False) -> dict[str, dict[str, dict[str, bool | str]]]:
|
|
27
|
+
"""Check if an update is available for Reachy Mini Wireless."""
|
|
28
|
+
if busy_lock.locked():
|
|
29
|
+
raise HTTPException(status_code=400, detail="Update is in progress")
|
|
30
|
+
|
|
31
|
+
current_version = str(get_local_version("reachy_mini"))
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
is_available = is_update_available("reachy_mini", pre_release)
|
|
35
|
+
available = str(get_pypi_version("reachy_mini", pre_release))
|
|
36
|
+
except (ConnectionError, requests.exceptions.ConnectionError):
|
|
37
|
+
is_available = False
|
|
38
|
+
available = "unknown"
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
"update": {
|
|
42
|
+
"reachy_mini": {
|
|
43
|
+
"is_available": is_available,
|
|
44
|
+
"current_version": current_version,
|
|
45
|
+
"available_version": available,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@router.post("/start")
|
|
52
|
+
def start_update(pre_release: bool = False) -> dict[str, str]:
|
|
53
|
+
"""Start the update process for Reachy Mini Wireless version."""
|
|
54
|
+
if busy_lock.locked():
|
|
55
|
+
raise HTTPException(status_code=400, detail="Update already in progress")
|
|
56
|
+
|
|
57
|
+
if not is_update_available("reachy_mini", pre_release):
|
|
58
|
+
raise HTTPException(status_code=400, detail="No update available")
|
|
59
|
+
|
|
60
|
+
async def update_wrapper(logger: logging.Logger) -> None:
|
|
61
|
+
with busy_lock:
|
|
62
|
+
await update_reachy_mini(pre_release, logger)
|
|
63
|
+
|
|
64
|
+
job_uuid = bg_job_register.run_command(
|
|
65
|
+
"update_reachy_mini",
|
|
66
|
+
update_wrapper,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
return {"job_id": job_uuid}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@router.get("/info")
|
|
73
|
+
def get_update_info(job_id: str) -> JobInfo:
|
|
74
|
+
"""Get the info of an update job."""
|
|
75
|
+
try:
|
|
76
|
+
return bg_job_register.get_info(job_id)
|
|
77
|
+
except ValueError as e:
|
|
78
|
+
raise HTTPException(status_code=404, detail=str(e))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@router.websocket("/ws/logs")
|
|
82
|
+
async def websocket_logs(websocket: WebSocket, job_id: str) -> None:
|
|
83
|
+
"""WebSocket endpoint to stream update logs in real time."""
|
|
84
|
+
await websocket.accept()
|
|
85
|
+
await bg_job_register.ws_poll_info(websocket, job_id)
|
|
86
|
+
await websocket.close()
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"""Volume control API routes.
|
|
2
|
+
|
|
3
|
+
This exposes:
|
|
4
|
+
- get current volume
|
|
5
|
+
- set volume
|
|
6
|
+
- same for microphone
|
|
7
|
+
- play test sound (optional)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
import platform
|
|
12
|
+
import subprocess
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
from fastapi import APIRouter, Depends, HTTPException
|
|
16
|
+
from pydantic import BaseModel, Field
|
|
17
|
+
|
|
18
|
+
from reachy_mini.daemon.app.dependencies import get_backend
|
|
19
|
+
from reachy_mini.daemon.backend.abstract import Backend
|
|
20
|
+
|
|
21
|
+
router = APIRouter(prefix="/volume")
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
# Constants
|
|
25
|
+
AUDIO_COMMAND_TIMEOUT = 2 # Timeout in seconds for audio commands
|
|
26
|
+
|
|
27
|
+
# Device-specific card names for amixer
|
|
28
|
+
DEVICE_CARD_NAMES = {
|
|
29
|
+
"reachy_mini_audio": "Audio", # Reachy Mini Audio device
|
|
30
|
+
"respeaker": "Array", # Legacy ReSpeaker device
|
|
31
|
+
"default": "Audio", # Default to Reachy Mini Audio
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class VolumeRequest(BaseModel):
|
|
36
|
+
"""Request model for setting volume."""
|
|
37
|
+
|
|
38
|
+
volume: int = Field(..., ge=0, le=100, description="Volume level (0-100)")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class VolumeResponse(BaseModel):
|
|
42
|
+
"""Response model for volume operations."""
|
|
43
|
+
|
|
44
|
+
volume: int
|
|
45
|
+
device: str
|
|
46
|
+
platform: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TestSoundResponse(BaseModel):
|
|
50
|
+
"""Response model for test sound operations."""
|
|
51
|
+
|
|
52
|
+
status: str
|
|
53
|
+
message: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_current_platform() -> str:
|
|
57
|
+
"""Get the current platform."""
|
|
58
|
+
system = platform.system()
|
|
59
|
+
if system == "Darwin":
|
|
60
|
+
return "macOS"
|
|
61
|
+
elif system == "Linux":
|
|
62
|
+
return "Linux"
|
|
63
|
+
else:
|
|
64
|
+
return system
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def detect_audio_device() -> str:
|
|
68
|
+
"""Detect the current audio output device."""
|
|
69
|
+
system = platform.system()
|
|
70
|
+
|
|
71
|
+
if system == "Linux":
|
|
72
|
+
# Try to detect if Reachy Mini Audio or legacy Respeaker is available
|
|
73
|
+
try:
|
|
74
|
+
result = subprocess.run(
|
|
75
|
+
["aplay", "-l"],
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
79
|
+
)
|
|
80
|
+
output_lower = result.stdout.lower()
|
|
81
|
+
if "reachy mini audio" in output_lower:
|
|
82
|
+
return "reachy_mini_audio"
|
|
83
|
+
elif "respeaker" in output_lower:
|
|
84
|
+
return "respeaker"
|
|
85
|
+
except (subprocess.TimeoutExpired, FileNotFoundError):
|
|
86
|
+
pass
|
|
87
|
+
return "default"
|
|
88
|
+
elif system == "Darwin":
|
|
89
|
+
return "system"
|
|
90
|
+
else:
|
|
91
|
+
return "unknown"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_linux_card_name() -> str:
|
|
95
|
+
"""Get the appropriate card name for Linux amixer commands based on detected device."""
|
|
96
|
+
device = detect_audio_device()
|
|
97
|
+
return DEVICE_CARD_NAMES.get(device, DEVICE_CARD_NAMES["default"])
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# macOS Volume Control
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_volume_macos() -> Optional[int]:
|
|
104
|
+
"""Get current system volume on macOS."""
|
|
105
|
+
try:
|
|
106
|
+
result = subprocess.run(
|
|
107
|
+
["osascript", "-e", "output volume of (get volume settings)"],
|
|
108
|
+
capture_output=True,
|
|
109
|
+
text=True,
|
|
110
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
111
|
+
)
|
|
112
|
+
if result.returncode == 0:
|
|
113
|
+
return int(result.stdout.strip())
|
|
114
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e:
|
|
115
|
+
logger.error(f"Failed to get macOS volume: {e}")
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def set_volume_macos(volume: int) -> bool:
|
|
120
|
+
"""Set system volume on macOS using osascript."""
|
|
121
|
+
try:
|
|
122
|
+
subprocess.run(
|
|
123
|
+
["osascript", "-e", f"set volume output volume {volume}"],
|
|
124
|
+
capture_output=True,
|
|
125
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
126
|
+
check=True,
|
|
127
|
+
)
|
|
128
|
+
return True
|
|
129
|
+
except (
|
|
130
|
+
subprocess.TimeoutExpired,
|
|
131
|
+
FileNotFoundError,
|
|
132
|
+
subprocess.CalledProcessError,
|
|
133
|
+
) as e:
|
|
134
|
+
logger.error(f"Failed to set macOS volume: {e}")
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# Linux Volume Control
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def get_volume_linux() -> Optional[int]:
|
|
142
|
+
"""Get current volume on Linux using amixer."""
|
|
143
|
+
card_name = get_linux_card_name()
|
|
144
|
+
try:
|
|
145
|
+
result = subprocess.run(
|
|
146
|
+
["amixer", "-c", card_name, "sget", "PCM"],
|
|
147
|
+
capture_output=True,
|
|
148
|
+
text=True,
|
|
149
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
150
|
+
)
|
|
151
|
+
if result.returncode == 0:
|
|
152
|
+
# Parse output to extract volume percentage
|
|
153
|
+
for line in result.stdout.splitlines():
|
|
154
|
+
if "Left:" in line and "[" in line:
|
|
155
|
+
# Extract percentage between brackets
|
|
156
|
+
parts = line.split("[")
|
|
157
|
+
for part in parts:
|
|
158
|
+
if "%" in part:
|
|
159
|
+
volume_str = part.split("%")[0]
|
|
160
|
+
return int(volume_str)
|
|
161
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e:
|
|
162
|
+
logger.error(f"Failed to get Linux volume: {e}")
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def set_volume_linux(volume: int) -> bool:
|
|
167
|
+
"""Set current volume on Linux using amixer."""
|
|
168
|
+
card_name = get_linux_card_name()
|
|
169
|
+
try:
|
|
170
|
+
subprocess.run(
|
|
171
|
+
["amixer", "-c", card_name, "sset", "PCM", f"{volume}%"],
|
|
172
|
+
capture_output=True,
|
|
173
|
+
text=True,
|
|
174
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
175
|
+
check=True,
|
|
176
|
+
)
|
|
177
|
+
subprocess.run(
|
|
178
|
+
["amixer", "-c", card_name, "sset", "PCM,1", "100%"],
|
|
179
|
+
capture_output=True,
|
|
180
|
+
text=True,
|
|
181
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
182
|
+
check=True,
|
|
183
|
+
)
|
|
184
|
+
return True
|
|
185
|
+
except (
|
|
186
|
+
subprocess.TimeoutExpired,
|
|
187
|
+
FileNotFoundError,
|
|
188
|
+
subprocess.CalledProcessError,
|
|
189
|
+
ValueError,
|
|
190
|
+
) as e:
|
|
191
|
+
logger.error(f"Failed to set Linux volume: {e}")
|
|
192
|
+
return False
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# API Endpoints - Speaker Volume
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@router.get("/current")
|
|
199
|
+
async def get_volume() -> VolumeResponse:
|
|
200
|
+
"""Get the current volume level."""
|
|
201
|
+
system = get_current_platform()
|
|
202
|
+
device = detect_audio_device()
|
|
203
|
+
|
|
204
|
+
volume = None
|
|
205
|
+
if system == "macOS":
|
|
206
|
+
volume = get_volume_macos()
|
|
207
|
+
elif system == "Linux":
|
|
208
|
+
volume = get_volume_linux()
|
|
209
|
+
|
|
210
|
+
if volume is None:
|
|
211
|
+
raise HTTPException(status_code=500, detail="Failed to get volume")
|
|
212
|
+
|
|
213
|
+
return VolumeResponse(volume=volume, device=device, platform=system)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@router.post("/set")
|
|
217
|
+
async def set_volume(
|
|
218
|
+
volume_req: VolumeRequest,
|
|
219
|
+
backend: Backend = Depends(get_backend),
|
|
220
|
+
) -> VolumeResponse:
|
|
221
|
+
"""Set the volume level and play a test sound."""
|
|
222
|
+
system = get_current_platform()
|
|
223
|
+
device = detect_audio_device()
|
|
224
|
+
|
|
225
|
+
success = False
|
|
226
|
+
if system == "macOS":
|
|
227
|
+
success = set_volume_macos(volume_req.volume)
|
|
228
|
+
elif system == "Linux":
|
|
229
|
+
success = set_volume_linux(volume_req.volume)
|
|
230
|
+
else:
|
|
231
|
+
raise HTTPException(
|
|
232
|
+
status_code=501,
|
|
233
|
+
detail=f"Volume control not supported on {system}",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
if not success:
|
|
237
|
+
raise HTTPException(status_code=500, detail="Failed to set volume")
|
|
238
|
+
|
|
239
|
+
# Play test sound
|
|
240
|
+
test_sound = "impatient1.wav"
|
|
241
|
+
if backend.audio:
|
|
242
|
+
try:
|
|
243
|
+
backend.audio.play_sound(test_sound)
|
|
244
|
+
except Exception as e:
|
|
245
|
+
msg = str(e).lower()
|
|
246
|
+
if "device unavailable" in msg or "-9985" in msg:
|
|
247
|
+
logger.warning(
|
|
248
|
+
"Test sound not played: audio device busy (likely GStreamer): %s",
|
|
249
|
+
e,
|
|
250
|
+
)
|
|
251
|
+
else:
|
|
252
|
+
logger.warning("Failed to play test sound: %s", e)
|
|
253
|
+
else:
|
|
254
|
+
logger.warning("No audio backend available, skipping test sound.")
|
|
255
|
+
|
|
256
|
+
return VolumeResponse(volume=volume_req.volume, device=device, platform=system)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@router.post("/test-sound")
|
|
260
|
+
async def play_test_sound(backend: Backend = Depends(get_backend)) -> TestSoundResponse:
|
|
261
|
+
"""Play a test sound."""
|
|
262
|
+
test_sound = "impatient1.wav"
|
|
263
|
+
|
|
264
|
+
if not backend.audio:
|
|
265
|
+
raise HTTPException(status_code=503, detail="Audio device not available")
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
backend.audio.play_sound(test_sound)
|
|
269
|
+
return TestSoundResponse(status="ok", message="Test sound played")
|
|
270
|
+
except Exception as e:
|
|
271
|
+
msg = str(e).lower()
|
|
272
|
+
|
|
273
|
+
# Special-case ALSA / PortAudio device-busy situation
|
|
274
|
+
if "device unavailable" in msg or "-9985" in msg:
|
|
275
|
+
logger.warning(
|
|
276
|
+
"Test sound request while audio device is busy (likely GStreamer): %s",
|
|
277
|
+
e,
|
|
278
|
+
)
|
|
279
|
+
# Still 200, but tell the caller it was skipped
|
|
280
|
+
return TestSoundResponse(
|
|
281
|
+
status="busy",
|
|
282
|
+
message="Audio device is currently in use, test sound was skipped.",
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Any other error is treated as a real failure
|
|
286
|
+
logger.error("Failed to play test sound: %s", e, exc_info=True)
|
|
287
|
+
raise HTTPException(
|
|
288
|
+
status_code=500,
|
|
289
|
+
detail="Failed to play test sound (see logs for details)",
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# macOS Microphone Control
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def get_microphone_volume_macos() -> Optional[int]:
|
|
297
|
+
"""Get current microphone input volume on macOS."""
|
|
298
|
+
try:
|
|
299
|
+
result = subprocess.run(
|
|
300
|
+
["osascript", "-e", "input volume of (get volume settings)"],
|
|
301
|
+
capture_output=True,
|
|
302
|
+
text=True,
|
|
303
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
304
|
+
)
|
|
305
|
+
if result.returncode == 0:
|
|
306
|
+
return int(result.stdout.strip())
|
|
307
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e:
|
|
308
|
+
logger.error(f"Failed to get macOS microphone volume: {e}")
|
|
309
|
+
return None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def set_microphone_volume_macos(volume: int) -> bool:
|
|
313
|
+
"""Set microphone input volume on macOS using osascript."""
|
|
314
|
+
try:
|
|
315
|
+
subprocess.run(
|
|
316
|
+
["osascript", "-e", f"set volume input volume {volume}"],
|
|
317
|
+
capture_output=True,
|
|
318
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
319
|
+
check=True,
|
|
320
|
+
)
|
|
321
|
+
return True
|
|
322
|
+
except (
|
|
323
|
+
subprocess.TimeoutExpired,
|
|
324
|
+
FileNotFoundError,
|
|
325
|
+
subprocess.CalledProcessError,
|
|
326
|
+
) as e:
|
|
327
|
+
logger.error(f"Failed to set macOS microphone volume: {e}")
|
|
328
|
+
return False
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# Linux Microphone Control
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def get_microphone_volume_linux() -> Optional[int]:
|
|
335
|
+
"""Get current microphone input volume on Linux using amixer."""
|
|
336
|
+
card_name = get_linux_card_name()
|
|
337
|
+
try:
|
|
338
|
+
result = subprocess.run(
|
|
339
|
+
["amixer", "-c", card_name, "sget", "Headset"],
|
|
340
|
+
capture_output=True,
|
|
341
|
+
text=True,
|
|
342
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
343
|
+
)
|
|
344
|
+
if result.returncode == 0:
|
|
345
|
+
# Parse output to extract volume percentage
|
|
346
|
+
for line in result.stdout.splitlines():
|
|
347
|
+
if "Left:" in line and "[" in line:
|
|
348
|
+
parts = line.split("[")
|
|
349
|
+
for part in parts:
|
|
350
|
+
if "%" in part:
|
|
351
|
+
volume_str = part.split("%")[0]
|
|
352
|
+
return int(volume_str)
|
|
353
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, ValueError) as e:
|
|
354
|
+
logger.error(f"Failed to get Linux microphone volume: {e}")
|
|
355
|
+
return None
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def set_microphone_volume_linux(volume: int) -> bool:
|
|
359
|
+
"""Set microphone input volume on Linux using amixer."""
|
|
360
|
+
card_name = get_linux_card_name()
|
|
361
|
+
try:
|
|
362
|
+
subprocess.run(
|
|
363
|
+
["amixer", "-c", card_name, "sset", "Headset", f"{volume}%"],
|
|
364
|
+
capture_output=True,
|
|
365
|
+
text=True,
|
|
366
|
+
timeout=AUDIO_COMMAND_TIMEOUT,
|
|
367
|
+
check=True,
|
|
368
|
+
)
|
|
369
|
+
return True
|
|
370
|
+
except (
|
|
371
|
+
subprocess.TimeoutExpired,
|
|
372
|
+
FileNotFoundError,
|
|
373
|
+
subprocess.CalledProcessError,
|
|
374
|
+
ValueError,
|
|
375
|
+
) as e:
|
|
376
|
+
logger.error(f"Failed to set Linux microphone volume: {e}")
|
|
377
|
+
return False
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# API Endpoints - Microphone Volume
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
@router.get("/microphone/current")
|
|
384
|
+
async def get_microphone_volume() -> VolumeResponse:
|
|
385
|
+
"""Get the current microphone input volume level."""
|
|
386
|
+
system = get_current_platform()
|
|
387
|
+
device = detect_audio_device()
|
|
388
|
+
|
|
389
|
+
volume = None
|
|
390
|
+
if system == "macOS":
|
|
391
|
+
volume = get_microphone_volume_macos()
|
|
392
|
+
elif system == "Linux":
|
|
393
|
+
volume = get_microphone_volume_linux()
|
|
394
|
+
|
|
395
|
+
if volume is None:
|
|
396
|
+
raise HTTPException(status_code=500, detail="Failed to get microphone volume")
|
|
397
|
+
|
|
398
|
+
return VolumeResponse(volume=volume, device=device, platform=system)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
@router.post("/microphone/set")
|
|
402
|
+
async def set_microphone_volume(
|
|
403
|
+
volume_req: VolumeRequest,
|
|
404
|
+
) -> VolumeResponse:
|
|
405
|
+
"""Set the microphone input volume level."""
|
|
406
|
+
system = get_current_platform()
|
|
407
|
+
device = detect_audio_device()
|
|
408
|
+
|
|
409
|
+
success = False
|
|
410
|
+
if system == "macOS":
|
|
411
|
+
success = set_microphone_volume_macos(volume_req.volume)
|
|
412
|
+
elif system == "Linux":
|
|
413
|
+
success = set_microphone_volume_linux(volume_req.volume)
|
|
414
|
+
else:
|
|
415
|
+
raise HTTPException(
|
|
416
|
+
status_code=501,
|
|
417
|
+
detail=f"Microphone volume control not supported on {system}",
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
if not success:
|
|
421
|
+
raise HTTPException(status_code=500, detail="Failed to set microphone volume")
|
|
422
|
+
|
|
423
|
+
return VolumeResponse(volume=volume_req.volume, device=device, platform=system)
|