diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml
index 5f66ece4..c84cd1ee 100644
--- a/.github/workflows/greetings.yml
+++ b/.github/workflows/greetings.yml
@@ -9,8 +9,23 @@ jobs:
issues: write
pull-requests: write
steps:
+ # Check if the issue or PR already has the greeted label
+ - name: Check if Already Greeted
+ id: check_greeted
+ uses: actions/github-script@v6
+ with:
+ result-encoding: string
+ script: |
+ const labels = await github.rest.issues.listLabelsOnIssue({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo
+ });
+ return labels.data.some(label => label.name === 'greeted');
+
# Greeting for first interaction using actions/first-interaction
- name: First Interaction Greeting
+ if: steps.check_greeted.outputs.result == 'false'
uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
@@ -19,7 +34,7 @@ jobs:
# General greeting for every new issue
- name: Greet Every Issue
- if: github.event_name == 'issues'
+ if: github.event_name == 'issues' && steps.check_greeted.outputs.result == 'false'
uses: actions/github-script@v6
with:
script: |
@@ -29,11 +44,11 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
body: issueComment
- })
+ });
# General greeting for every new pull request
- name: Greet Every PR
- if: github.event_name == 'pull_request_target'
+ if: github.event_name == 'pull_request_target' && steps.check_greeted.outputs.result == 'false'
uses: actions/github-script@v6
with:
script: |
@@ -44,33 +59,25 @@ jobs:
repo: context.repo.repo,
body: prComment,
event: 'COMMENT'
- })
+ });
# Add labels to new issues and PRs
- name: Label New Issues and PRs
+ if: steps.check_greeted.outputs.result == 'false'
uses: actions/github-script@v6
with:
script: |
- const labels = ['needs-triage'];
- if (context.eventName === 'issues') {
- github.rest.issues.addLabels({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- labels: labels
- })
- } else if (context.eventName === 'pull_request_target') {
- github.rest.issues.addLabels({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- labels: labels
- })
- }
+ const labels = ['needs-triage', 'greeted'];
+ github.rest.issues.addLabels({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ labels: labels
+ });
# Auto Assign Reviewers based on the time of day
- name: Auto-assign Reviewers Based on Time of Day
- if: github.event_name == 'pull_request_target'
+ if: github.event_name == 'pull_request_target' && steps.check_greeted.outputs.result == 'false'
uses: actions/github-script@v6
with:
script: |
@@ -82,4 +89,4 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
reviewers: reviewers
- })
+ });
diff --git a/.github/workflows/windows-mingw.yml b/.github/workflows/windows-mingw.yml
index 42c39043..1d3b6838 100644
--- a/.github/workflows/windows-mingw.yml
+++ b/.github/workflows/windows-mingw.yml
@@ -6,10 +6,12 @@ on:
branches:
- 'master'
- 'dev'
+ - 'reborn'
pull_request:
branches:
- 'master'
- 'dev'
+ - 'reborn'
env:
# Path to the solution file relative to the root of the project.
@@ -43,7 +45,6 @@ jobs:
update: true
install: >-
mingw-w64-${{matrix.env}}-openssl
-
base-devel
mingw-w64-${{matrix.env}}-cmake
mingw-w64-${{matrix.env}}-gcc
@@ -58,9 +59,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- - name: Build INDI Core
+ - name: Build and Test
run: |
- mkdir build
- cd build
- cmake ..
- cmake --build .
+ ./scripts/build_win.sh
+ ./scripts/test_win.sh
diff --git a/.gitignore b/.gitignore
index aa7184a5..03d90896 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,3 +49,8 @@ test
*.xml
.xmake
+.cache
+
+cmake-build-debug/
+
+.venv/
diff --git a/.gitmodules b/.gitmodules
index bac355b9..ddb22ab7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "libs"]
path = libs
- url = https://github.com/ElementAstro/LithiumLibrary.git
\ No newline at end of file
+ url = https://github.com/ElementAstro/LithiumLibrary.git
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..13566b81
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/Lithium.iml b/.idea/Lithium.iml
new file mode 100644
index 00000000..8afe22e0
--- /dev/null
+++ b/.idea/Lithium.iml
@@ -0,0 +1,2 @@
+
+
diff --git a/.sonarlint/connectedMode.json b/.sonarlint/connectedMode.json
new file mode 100644
index 00000000..26648e83
--- /dev/null
+++ b/.sonarlint/connectedMode.json
@@ -0,0 +1,4 @@
+{
+ "sonarCloudOrganization": "elementastro",
+ "projectKey": "ElementAstro_Lithium"
+}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce2d2377..eb3b879d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,35 +66,164 @@ include_directories(${CMAKE_SOURCE_DIR}/libs/)
include_directories(${CMAKE_SOURCE_DIR}/driverlibs/)
include_directories(${lithium_src_dir})
include_directories(${lithium_module_dir})
-include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp)
-include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp-swagger)
-include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp-websocket)
+include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp/oatpp)
+include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp-swagger/oatpp-swagger)
+include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp-websocket/oatpp-websocket)
+include_directories(${CMAKE_SOURCE_DIR}/libs/oatpp-openssl/oatpp-openssl)
# Find packages
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(fmt REQUIRED)
+find_package(Readline REQUIRED)
+
+find_package(Python COMPONENTS Interpreter REQUIRED)
+
+# Specify the path to requirements.txt
+set(REQUIREMENTS_FILE "${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt")
+
+# Define a function to check if a Python package is installed
+function(check_python_package package version)
+ # Replace hyphens with underscores for the import statement
+ string(REPLACE "-" "_" import_name ${package})
+
+ # Check if the package can be imported
+ execute_process(
+ COMMAND ${Python_EXECUTABLE} -c "import ${import_name}"
+ RESULT_VARIABLE result
+ )
+
+ if(NOT result EQUAL 0)
+ set(result FALSE PARENT_SCOPE)
+ return()
+ endif()
+
+ # Get the installed package version
+ execute_process(
+ COMMAND ${Python_EXECUTABLE} -m pip show ${package}
+ OUTPUT_VARIABLE package_info
+ )
+
+ # Extract version information from the output
+ string(FIND "${package_info}" "Version:" version_pos)
+
+ if(version_pos EQUAL -1)
+ set(result FALSE PARENT_SCOPE)
+ return() # Return false if version not found
+ endif()
+
+ # Extract the version string
+ string(SUBSTRING "${package_info}" ${version_pos} 1000 version_string)
+ string(REGEX REPLACE "Version: ([^ ]+).*" "\\1" installed_version "${version_string}")
+
+ # Compare versions
+ if("${installed_version}" VERSION_LESS "${version}")
+ set(result FALSE PARENT_SCOPE) # Return false if installed version is less than required
+ return()
+ endif()
+
+ set(result TRUE PARENT_SCOPE)
+endfunction()
+
+if (EXISTS "${CMAKE_BINARY_DIR}/check_marker.txt")
+ message(STATUS "Check marker file found, skipping the checks.")
+else()
+# Create a virtual environment
+set(VENV_DIR "${CMAKE_BINARY_DIR}/venv")
+execute_process(
+ COMMAND ${Python_EXECUTABLE} -m venv ${VENV_DIR}
+)
+
+set(PYTHON_EXECUTABLE "${VENV_DIR}/bin/python")
+set(PIP_EXECUTABLE "${VENV_DIR}/bin/pip")
+
+# Upgrade pip in the virtual environment
+execute_process(
+ COMMAND ${PIP_EXECUTABLE} install --upgrade pip
+)
+
+# Read the requirements.txt file and install missing packages
+file(READ ${REQUIREMENTS_FILE} requirements_content)
+
+# Split the requirements file content into lines
+string(REPLACE "\n" ";" requirements_list "${requirements_content}")
+
+# Check and install each package
+foreach(requirement ${requirements_list})
+ # Skip empty lines
+ string(STRIP ${requirement} trimmed_requirement)
+ if(trimmed_requirement STREQUAL "")
+ continue()
+ endif()
+
+ # Get the package name and version (without the version number)
+ if(${trimmed_requirement} MATCHES "==")
+ string(REPLACE "==" ";" parts ${trimmed_requirement})
+ elseif(${trimmed_requirement} MATCHES ">=")
+ string(REPLACE ">=" ";" parts ${trimmed_requirement})
+ else()
+ message(WARNING "Could not parse requirement '${trimmed_requirement}'. Skipping...")
+ continue()
+ endif()
+
+ list(GET parts 0 package_name)
+ list(GET parts 1 package_version)
+
+ # If the package name or version could not be parsed, output a warning and skip
+ if(NOT package_name OR NOT package_version)
+ message(WARNING "Could not parse requirement '${trimmed_requirement}'. Skipping...")
+ continue()
+ endif()
+
+ # Check if the package is installed
+ message(STATUS "Checking if Python package '${package_name}' is installed...")
+ check_python_package(${package_name} ${package_version})
+ if(NOT result)
+ message(STATUS "Package '${package_name}' is not installed or needs an upgrade. Installing...")
+ execute_process(
+ COMMAND ${PIP_EXECUTABLE} install ${trimmed_requirement}
+ RESULT_VARIABLE install_result
+ )
+ if(NOT install_result EQUAL 0)
+ message(FATAL_ERROR "Failed to install Python package '${package_name}'.")
+ endif()
+ else()
+ message(STATUS "Package '${package_name}' is already installed with a suitable version.")
+ endif()
+endforeach()
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/check_marker.txt"
+ RESULT_VARIABLE result
+)
+endif()
# Configure config.h
-configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+configure_file(${lithium_src_dir}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+set(BUILD_SHARED_LIBS ON)
# Add subdirectories
add_subdirectory(libs)
-add_subdirectory(${lithium_module_dir})
add_subdirectory(modules)
-add_subdirectory(driver)
+add_subdirectory(${lithium_module_dir})
add_subdirectory(${lithium_src_dir}/config)
+add_subdirectory(${lithium_src_dir}/task)
+add_subdirectory(${lithium_src_dir}/server)
+add_subdirectory(${lithium_src_dir}/utils)
+add_subdirectory(${lithium_src_dir}/addon)
+add_subdirectory(${lithium_src_dir}/client)
+add_subdirectory(${lithium_src_dir}/device)
add_subdirectory(tests)
# Set source files
set(component_module
${lithium_component_dir}/addons.cpp
${lithium_component_dir}/compiler.cpp
+ ${lithium_component_dir}/dependency.cpp
${lithium_component_dir}/loader.cpp
${lithium_component_dir}/manager.cpp
${lithium_component_dir}/sandbox.cpp
- ${lithium_component_dir}/sort.cpp
)
set(config_module
@@ -106,25 +235,24 @@ set(debug_module
${lithium_src_dir}/debug/suggestion.cpp
${lithium_src_dir}/debug/command.cpp
${lithium_src_dir}/debug/console.cpp
+ ${lithium_src_dir}/debug/history.cpp
+ ${lithium_src_dir}/debug/progress.cpp
+ ${lithium_src_dir}/debug/output_style.cpp
+ ${lithium_src_dir}/debug/check.cpp
+)
+
+set(device_module
+ ${lithium_src_dir}/device/manager.cpp
+
+ ${lithium_src_dir}/device/template/device.cpp
+ ${lithium_src_dir}/device/template/camera.cpp
)
set(script_module
${lithium_src_dir}/script/manager.cpp
- ${lithium_src_dir}/script/custom/sys.cpp
- ${lithium_src_dir}/script/custom/config.cpp
${lithium_src_dir}/script/sheller.cpp
)
-set(task_module
- ${lithium_task_dir}/manager.cpp
- ${lithium_task_dir}/generator.cpp
- ${lithium_task_dir}/container.cpp
- ${lithium_task_dir}/tick.cpp
- ${lithium_task_dir}/loader.cpp
- ${lithium_task_dir}/list.cpp
- ${lithium_task_dir}/pool.cpp
-)
-
set(Lithium_module
${lithium_src_dir}/LithiumApp.cpp
${lithium_src_dir}/utils/constant.cpp
@@ -135,8 +263,8 @@ add_library(lithium_server-library STATIC
${component_module}
${config_module}
${debug_module}
+ ${device_module}
${script_module}
- ${task_module}
${Lithium_module}
)
@@ -152,25 +280,26 @@ add_executable(lithium_server ${lithium_src_dir}/App.cpp)
target_link_libraries(lithium_server
PRIVATE
lithium_server-library
- lithium_webserver
+ lithium.server-lib
+ lithium-config
+ lithium-task
+ lithium-addons
oatpp-websocket
oatpp-swagger
oatpp-openssl
oatpp-zlib
oatpp
loguru
- libzippp
- atomstatic
- carbon
+ atom
fmt::fmt
OpenSSL::SSL
OpenSSL::Crypto
${ZLIB_LIBRARIES}
sqlite3
cpp_httplib
- backward
tinyxml2
pocketpy
+ ${Readline_LIBRARIES}
)
if(WIN32)
@@ -187,6 +316,11 @@ if(WIN32)
)
elseif(UNIX OR LINUX OR APPLE)
target_link_libraries(lithium_server PRIVATE dl)
+ find_package(Seccomp REQUIRED)
+ if(Seccomp_FOUND)
+ include_directories(${Seccomp_INCLUDE_DIRS})
+ target_link_libraries(lithium_server PRIVATE ${Seccomp_LIBRARIES})
+ endif()
else()
message(FATAL_ERROR "Unsupported platform")
endif()
diff --git a/README.md b/README.md
index 14388641..24c27eb1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Lithium
+# Lithium - The Lightweight Suite for Astronomical Imaging
@@ -15,138 +15,54 @@
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=bugs)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
-## Introduction
+## Overview
-Lithium, a lively and lightweight astrophotography terminal.
+The Lithium project is designed as a comprehensive, lightweight platform for astronomy enthusiasts and professionals alike, offering not just capture software but also serving as a device control server, system manager, and a platform for extensive customization, adaptable to various applications and research domains.
-Features:
+## Key Features
-- Can be used as imaging software, device server, and system manager.
-- Based on the latest C++20 standard, providing efficient functionality implementation (compatible with some C++17 features).
-- Supports open loading, allowing dynamic loading of C++ dynamic libraries for hot updates.
-- Built-in optimized Chaiscript parsing engine, providing flexible script support.
-- Supports various types of plugins, facilitating feature expansion.
-- Cross-platform compatibility, fully supporting Windows and Linux operating systems.
-- Lightweight software design, while maintaining excellent performance.
-- Provides a rich API, covering all necessary functions for astrophotography. ~~If not? Mods!~~
-- Supports complex shooting sequences, enabling a programmable user experience.
-- Uses the GPL3 open source license, **where the world belongs to open source**
+- **Versatile Functionality**: Supports full-spectrum application from image acquisition to device management and system operations.
+- **Contemporary Language Standard**: Built using the latest C++20 standard with compatibility for select C++23 features, ensuring modernity and efficiency in code.
+- **Dynamic Module Loading**: Enables hot updates through C++ dynamic libraries, facilitating instant expansion of capabilities and enhancing flexibility.
+- **Embedded Scripting Engine**: Integrates a high-performance pocketpy interpreter supporting Python scripts for rapid development of tailored logic.
+- **Broad Platform Compatibility**: Fully supports Windows and Linux environments (including x86_64 and ARM architectures), with partial support for MacOS.
+- **Comprehensive APIs and Components**: Offers a wide range of APIs and functional components that cater to diverse astronomical imaging needs, encouraging users to develop modules for missing functionalities.
+- **Open-Source Licensing Model**: Adheres to the GPLv3 license, fostering community sharing and collaboration while allowing for proprietary plugins to protect business-sensitive code.
+- **Educational and Inspirational**: Encourages learning and innovation through high-quality code examples and documentation, promoting knowledge dissemination and skill enhancement.
-## About Mod/Plugin
+## Building Instructions
-In Lithium, the component function is the most special function, providing a mod mechanism similar to Minecraft. The component function supports dynamic addition and insertion of functions, but due to the limitations of C++, we have imposed certain restrictions on the insertion of components to ensure system stability and security.
+### System Preparation
-### Form of Components
+#### Windows
-- Injective Components: These components replace the implemented functions in `Lithium`. They inject `shared_ptr` into each Manager (similar to `ConfigManager`). The target of the injected function is the same as that of the Manager that has been injected into `GlobalPtrManager`. Components in this form can flexibly replace existing functions.
-
-- Independent Components: These components use a distributed architecture and run in independent processes to ensure system security. When it is necessary to process sensitive data or perform complex calculations, these independent components can provide additional protection and isolation. To increase the security of components, `Lithium` also provides sandboxing functionality.
-
-It should be noted that except for injective and independent components, other forms of components will be considered illegal and unsupported for loading, and will be directly ignored by the system.
-
-### Component Levels
-
-- Addon: The highest level of component, containing a series of Modules and Components
-
-- Module: A module containing a dynamic library of an indefinite number of Components (depending on the platform)
-
-- Component: A `shared_ptr` of a specific actual function or an executable function
-
-All functions are declared in `package.json` for ease of use.
-
-## How to build
-
-### Install dependencies
-
-Although efforts have been made to minimize the use of libraries, a few dependencies still need to be installed.
-
-#### On Windows
+It is recommended to use the MSYS2 environment and leverage the Tsinghua University Open Source Software Mirror for expedited downloads. The following commands install necessary dependencies:
```shell
-sed -i "s#https\?://mirror.msys2.org/#https://mirrors.tuna.tsinghua.edu.cn/msys2/#g" /etc/pacman.d/mirrorlist*
-pacman -Syu
-pacman -S mingw-w64-x86_64-toolchain
-pacman -S mingw-w64-x86_64-dlfcn
-pacman -S mingw-w64-x86_64-cfitsio
-pacman -S mingw-w64-x86_64-cmake
-pacman -S mingw-w64-x86_64-libzip
-pacman -S mingw-w64-x86_64-zlib
-pacman -S mingw-w64-x86_64-fmt
-pacman -S mingw-w64-x86_64-libnova
-pacman -S mingw-w64-x86_64-gsl
-
-# for test
-pacman -S mingw-w64-x86_64-gtest
-```
-
-#### On Ubuntu or other similar Linux platforms (No INDI needed)
+# Add Tsinghua University mirror source
+sed -i 's|https://mirror.msys2.org/|https://mirrors.tuna.tsinghua.edu.cn/msys2/|g' /etc/pacman.d/mirrorlist.mingw64
+sed -i 's|https://mirror.msys2.org/|https://mirrors.tuna.tsinghua.edu.cn/msys2/|g' /etc/pacman.d/mirrorlist
-```shell
-sudo apt-get update && sudo apt-get upgrade -y
-sudo apt install gcc g++ cmake
-sudo apt install libcfitsio-dev zlib1g-dev libssl-dev libzip-dev libnova-dev libfmt-dev libudev-dev
-```
-
-Alternatively, you can directly run the provided script according to your platform:
-
-```shell
-sudo sh scripts/build_ci.sh
-sh scripts/build_win.sh
-```
-
-#### Update GCC and Cmake
-
-Unfortunately, the newest GCC and CMake are not available on Github Codespace, so we must install them manually.
-
-```shell
-sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
-sudo apt-get update
-sudo apt-get install gcc-13 g++-13 # GCC13 is the best choice, clang is alse OK
-
-wget https://cmake.org/files/v3.28/cmake-3.28.0-rc5.tar.gz
-tar -zxvf cmake-3.28.0-rc5.tar.gz
-cd cmake-3.28.0-rc5
-./bootstrap && make && sudo make install
-
-#install newest clang-format
-wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
-sudo nano /etc/apt/sources.list
-#deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main
-#deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main
-sudo apt install -y clang-format-17
+# Update system packages and install build tools and dependencies
+pacman -Syu
+pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-dlfcn mingw-w64-x86_64-cfitsio mingw-w64-x86_64-cmake mingw-w64-x86_64-libzip mingw-w64-x86_64-zlib mingw-w64-x86_64-fmt mingw-w64-x86_64-libnova make mingw-w64-x86_64-gtest
```
-Build the code:
+#### Ubuntu/Debian
```shell
-mkdir build && cd build
-cmake ..
-make -j4 or cmake --build . -j4
-
-./lithium_server
+sudo apt-get update && sudo apt-get upgrade
+sudo apt-get install build-essential cmake libcfitsio-dev zlib1g-dev libssl-dev libzip-dev libfmt-dev
```
-Everything is very simple. The entire process is straightforward.
+Alternatively, utilize the provided quick-build scripts to streamline the process.
-Here is a poem adapted from a quote :
+### Building Steps
-```txt
-Learning requires not mere imagination,
-Nor can it be attained through mediocre dedication.
-It is through diligent accumulation,
-That we shall grow in our education.
-
-Our efforts may falter and fail,
-But we must not surrender and bail.
-We shall not halt our stride for fear of stumbling,
-For setbacks are the price of pursuing enlightenment.
-
-On this quest for truth, we shall encounter obstacles and doubts,
-Yet we shall keep our resolve to seek understanding throughout.
-Let us nurture a heart that yearns for wisdom and grace,
-And never lose sight of this noble race.
-```
+1. **Create Build Directory**: `mkdir build && cd build`
+2. **Configure Project**: `cmake ..`
+3. **Compile and Execute**: Use `make -jN` or `cmake --build . --parallel N` commands to compile in parallel, where N denotes the number of threads. Afterwards, launch the program via `./lithium_server`.
-## Technical Support
+### Intellectual Inspiration
-[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-orange.svg)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
+Embarking on the journey with Lithium, we embrace curiosity and an unwavering pursuit of knowledge, echoing the adapted verse which reminds us that every attempt, though fraught with challenges and setbacks, is a necessary step toward wisdom and understanding. Together, let us navigate the vast cosmos of astronomical imaging, our technology the vessel, innovation our sail, advancing relentlessly forward.
diff --git a/README_ZH.md b/README_ZH.md
index 82848dda..263ae0d6 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -1,4 +1,4 @@
-# 锂
+# 锂 - 高度集成的天文摄影解决方案
@@ -15,112 +15,53 @@
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=bugs)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ElementAstro_Lithium&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ElementAstro_Lithium)
-## 简介
+## 概览
-锂,轻量化的开放加载框架
+锂项目旨在为天文摄影爱好者及专业人士提供一个高度整合、轻量级的综合平台。它不仅是一个拍摄软件,还兼具设备控制服务器、系统管理以及广泛的可定制扩展能力,适用于多种应用场景和研究领域。
-## 特性
+## 核心特性
-- 可用作成像软件、设备服务器和系统管理器,或者是其他轻量级应用
-- 基于最新的 C++20 标准,提供高效实现(兼容部分 **C++23** 特性)
-- 支持开放式加载,允许动态加载 C++动态库热更新,基于Atom架构
-- 内置经过优化的 Pocketpy 解析引擎,提供灵活的Python脚本支持
-- 跨平台兼容性,完全支持 Windows 和 Linux 操作系统
-- 提供丰富的 API,覆盖所有天文摄影所需功能,~~功能没有怎么办?写模组!~~
-- 采用 GPL3 开源许可协议,**世界属于开源**
+- **多面手功能**:支持从图像捕获到设备管理,乃至系统级操作的全方位应用。
+- **先进语言标准**:采用最新C++20标准编写,并兼容C++23部分特性,确保代码的现代性和高效性。
+- **动态模块加载**:通过C++动态库实现的热更新机制,允许用户即时扩展功能,增强灵活性。
+- **嵌入式脚本引擎**:集成高性能的pocketpy解析器,支持Python脚本,便于快速开发定制化逻辑。
+- **广泛平台兼容**:全面适配Windows与Linux环境(包括x86_64及ARM架构),并具备部分MacOS支持。
+- **丰富接口与组件**:提供全面的API接口和功能组件,满足天文摄影的多样化需求,鼓励用户开发缺失功能的模组。
+- **开源授权模式**:遵循GPLv3协议,促进社区共享与合作,同时允许开发闭源插件以保护商业敏感代码。
-## 模组/插件
+## 构建指南
-在 Lithium,组件功能是最特殊的功能,提供类似于 Minecraft 的模组机制。组件功能支持动态添加和插入功能,但由于 C++语言限制,组件功能没有办法做到像python等动态语言那样自由,具有一定的限制和标准:
+### 系统准备
-- 注入式组件:这些组件替换了`Lithium`中已实现的功能。它们通过使用`shared_ptr`注入各个 Manager(类似与`ConfigManager`),目标与已注入`GlobalPtrManager`的管理器相同。这种形式的组件可以灵活替换现有功能。
+#### Windows
-- 独立式组件:这些组件采用分布式架构,在独立的进程中运行,以确保系统的安全性。当需要处理敏感数据或进行复杂的计算时,这种独立的组件能够提供额外的保护和隔离。为了增加组件的安全性,`Lithium`还提供了沙盒功能.
-
-需要注意的是,除了注入式和独立式组件外,其他形式的组件都将被视为非法形式,不支持加载,并将被系统直接忽略。
-
-### 组件级别
-
-- Addon:最高级的组件,包含一系列的 Module 和 Component
-
-- Module:模块,包含不定数量 Component 的动态库(根据平台而定)
-
-- Component:组件,具体实际功能的`shared_ptr`,或者是可执行的函
-
-所有功能均在`package.json`中声明,以方便使用。
-
-## 如何构建
-
-### 安装依赖项
-
-尽管已经尽最大努力减少了库的使用,但仍需要安装一些依赖项
-
-#### 在 Windows 平台下
+推荐使用MSYS2环境,并通过清华大学开源软件镜像站加速下载。以下命令用于安装必要依赖:
```shell
-# 添加清华镜像源,下载速度嘎嘎的
-sed -i "s#https\?://mirror.msys2.org/#https://mirrors.tuna.tsinghua.edu.cn/msys2/#g" /etc/pacman.d/mirrorlist*
-pacman -Syu
-pacman -S mingw-w64-x86_64-toolchain
-pacman -S mingw-w64-x86_64-dlfcn
-pacman -S mingw-w64-x86_64-cfitsio
-pacman -S mingw-w64-x86_64-cmake
-pacman -S mingw-w64-x86_64-libzip
-pacman -S mingw-w64-x86_64-zlib
-pacman -S mingw-w64-x86_64-fmt
-pacman -S mingw-w64-x86_64-libnova
-# 如果想用make构建
-pacman -S make # 注意添加对应的目录,否则会当场爆炸
-
-pacman -S mingw-w64-x86_64-gsl
-
-# 测试用
-pacman -S mingw-w64-x86_64-gtest
-```
-
-#### Ubuntu/Debian/Other Linux
-
-```shell
-sudo apt-get update && sudo apt-get upgrade -y
-sudo apt install gcc g++ cmake
-sudo apt install libcfitsio-dev zlib1g-dev libssl-dev libzip-dev libnova-dev libfmt-dev
-```
+# 添加清华大学镜像源
+sed -i 's|https://mirror.msys2.org/|https://mirrors.tuna.tsinghua.edu.cn/msys2/|g' /etc/pacman.d/mirrorlist.mingw64
+sed -i 's|https://mirror.msys2.org/|https://mirrors.tuna.tsinghua.edu.cn/msys2/|g' /etc/pacman.d/mirrorlist
-或者您可以直接根据您的平台运行提供的脚本:
-
-```shell
-sudo sh scripts/build_ci.sh
-sh scripts/build_win.sh
+# 更新系统包并安装编译工具链等
+pacman -Syu
+pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-dlfcn mingw-w64-x86_64-cfitsio mingw-w64-x86_64-cmake mingw-w64-x86_64-libzip mingw-w64-x86_64-zlib mingw-w64-x86_64-fmt mingw-w64-x86_64-libnova make mingw-w64-x86_64-gtest
```
-#### 构建代码
+#### Ubuntu/Debian
```shell
-mkdir build && cd build
-cmake ..
-# -jn,n取决于你的电脑性能,一般是cpu核心数+2
-make -j4 或 cmake --build . -j4
-
-./lithium_server
+sudo apt-get update && sudo apt-get upgrade
+sudo apt-get install build-essential cmake libcfitsio-dev zlib1g-dev libssl-dev libzip-dev libfmt-dev
```
-一切都非常简单整个过程很简单
+或使用提供的快捷构建脚本简化过程。
-下面是一首小诗,改编自《三体》中的一句话:
+### 构建步骤
-```text
-学习不仅仅需要想象,
-也不能只凭平庸的奉献
-通过勤奋的积累,
-我们在教育中成长
+1. **创建构建目录**:`mkdir build && cd build`
+2. **配置项目**:`cmake ..`
+3. **编译执行**:使用`make -jN`或`cmake --build . -j N`命令进行并行编译,其中N为线程数。完成后,通过`./lithium_server`启动程序。
-我们的努力可能会摇摇欲坠,甚至失败,
-但我们不能放弃和退缩
-我们不应因为恐惧而停下脚步,
-因为挫折是追求智慧的代价
+### 思维启迪
-在这探寻真理的旅途上,我们会遇到困难和疑虑,
-但我们要始终坚定地追求理解
-让我们培养一颗渴望智慧和优雅的心灵,
-永远不要忘记这个崇高的竞赛
-```
+在深入探索锂项目的旅程中,我们秉承着对未知的好奇心与不懈的求知欲,正如那首改编的诗句所言,每一步尝试虽可能遭遇挑战与失败,却是通往智慧与理解的必经之路。让我们携手共进,在天文摄影的浩瀚星海中,以技术为舟,以创新为帆,不断前行。
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 00000000..a5e7a937
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,34 @@
+# TODO List for Project Lithium
+
+## High Priority
+
+- [ ] Complete the development of the OATPP server
+
+ - [ ] Complete the definition of HTTP and WS interfaces
+ - [ ] Implement all interfaces of q-box
+ - [ ] Complete user login verification
+
+- [ ] Complete the internal core of the server
+ - [ ] Implement internal message bus
+ - [ ] Implement internal task allocation mechanism
+
+## Medium Priority
+
+## Low Priority
+
+## Future Enhancements
+
+- [ ] Add support for additional languages
+ - [ ] Localization for Spanish and French
+ - [ ] Implement language selection feature
+
+## Completed Tasks
+
+- [x] Setup project structure
+- [x] Configure build system with CMake
+
+## Notes
+
+- Ensure all code follows the project's coding standards and guidelines.
+- Use the issue tracker for reporting bugs and tracking progress on larger tasks.
+- Regularly review and update this TODO list to reflect the current state of the project.
diff --git a/cmake_modules/FindGMock.cmake b/cmake_modules/FindGMock.cmake
new file mode 100644
index 00000000..8fb858fd
--- /dev/null
+++ b/cmake_modules/FindGMock.cmake
@@ -0,0 +1,34 @@
+# FindGMock.cmake
+# This module finds the Google Mock library
+
+# Set the name of the required package
+find_package(GTest REQUIRED)
+
+# Try to locate the GMock library
+find_path(GMOCK_INCLUDE_DIR NAMES gmock/gmock.h HINTS ${GTEST_INCLUDE_DIR} ${GTEST_ROOT} PATHS /usr/local/include /usr/include)
+
+find_library(GMOCK_LIBRARY NAMES gmock HINTS ${GTEST_LIBRARY_DIR} ${GTEST_ROOT} PATHS /usr/local/lib /usr/lib)
+
+find_library(GMOCK_MAIN_LIBRARY NAMES gmock_main HINTS ${GTEST_LIBRARY_DIR} ${GTEST_ROOT} PATHS /usr/local/lib /usr/lib)
+
+# Check if found
+if (GMOCK_INCLUDE_DIR AND GMOCK_LIBRARY)
+ set(GMOCK_FOUND TRUE)
+else()
+ set(GMOCK_FOUND FALSE)
+endif()
+
+# Provide the results of the search, either found or not found
+if (GMOCK_FOUND)
+ message(STATUS "Found Google Mock: ${GMOCK_LIBRARY}")
+ message(STATUS "Includes: ${GMOCK_INCLUDE_DIR}")
+
+ # Set the variables necessary for using GMock
+ set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR} PARENT_SCOPE)
+ set(GMOCK_LIBRARIES ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} PARENT_SCOPE)
+else()
+ message(WARNING "Google Mock not found, please install it or set the paths correctly.")
+endif()
+
+# Provide the version information if necessary
+# set(GMOCK_VERSION "x.y.z") # Optionally set the version
diff --git a/cmake_modules/FindINDI.cmake b/cmake_modules/FindINDI.cmake
index b6433aa1..a0e3bd2c 100644
--- a/cmake_modules/FindINDI.cmake
+++ b/cmake_modules/FindINDI.cmake
@@ -1,5 +1,5 @@
macro(_INDI_check_version)
- file(READ "${INDI_INCLUDE_DIR}/lithiumapi.h" _INDI_version_header)
+ file(READ "${INDI_INCLUDE_DIR}/indiapi.h" _INDI_version_header)
string(REGEX MATCH "#define INDI_VERSION_MAJOR[ \t]+([0-9]+)" _INDI_version_major_match "${_INDI_version_header}")
set(INDI_VERSION_MAJOR "${CMAKE_MATCH_1}")
diff --git a/cmake_modules/FindReadline.cmake b/cmake_modules/FindReadline.cmake
new file mode 100644
index 00000000..cb78aaa9
--- /dev/null
+++ b/cmake_modules/FindReadline.cmake
@@ -0,0 +1,27 @@
+# - Try to find the Readline library
+# Once done, this will define
+# Readline_FOUND - System has Readline
+# Readline_INCLUDE_DIRS - The Readline include directories
+# Readline_LIBRARIES - The libraries needed to use Readline
+
+find_path(Readline_INCLUDE_DIR
+ NAMES readline/readline.h
+ PATHS /usr/include /usr/local/include
+)
+
+find_library(Readline_LIBRARY
+ NAMES readline
+ PATHS /usr/lib /usr/local/lib
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Readline DEFAULT_MSG
+ Readline_LIBRARY Readline_INCLUDE_DIR
+)
+
+if(Readline_FOUND)
+ set(Readline_LIBRARIES ${Readline_LIBRARY})
+ set(Readline_INCLUDE_DIRS ${Readline_INCLUDE_DIR})
+endif()
+
+mark_as_advanced(Readline_INCLUDE_DIR Readline_LIBRARY)
diff --git a/cmake_modules/FindSeccomp.cmake b/cmake_modules/FindSeccomp.cmake
new file mode 100644
index 00000000..b8b31674
--- /dev/null
+++ b/cmake_modules/FindSeccomp.cmake
@@ -0,0 +1,30 @@
+# - Try to find libseccomp
+# Once done, this will define
+#
+# Seccomp_FOUND - system has libseccomp
+# Seccomp_INCLUDE_DIRS - the libseccomp include directories
+# Seccomp_LIBRARIES - link these to use libseccomp
+
+find_path(Seccomp_INCLUDE_DIR
+ NAMES seccomp.h
+ PATH_SUFFIXES seccomp
+ PATHS /usr/local/include /usr/include
+)
+
+find_library(Seccomp_LIBRARY
+ NAMES seccomp
+ PATHS /usr/local/lib /usr/lib
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Seccomp DEFAULT_MSG Seccomp_LIBRARY Seccomp_INCLUDE_DIR)
+
+if(Seccomp_FOUND)
+ set(Seccomp_LIBRARIES ${Seccomp_LIBRARY})
+ set(Seccomp_INCLUDE_DIRS ${Seccomp_INCLUDE_DIR})
+else()
+ set(Seccomp_LIBRARIES "")
+ set(Seccomp_INCLUDE_DIRS "")
+endif()
+
+mark_as_advanced(Seccomp_INCLUDE_DIR Seccomp_LIBRARY)
diff --git a/cmake_modules/Findtomlplusplus.cmake b/cmake_modules/Findtomlplusplus.cmake
deleted file mode 100644
index b12f8595..00000000
--- a/cmake_modules/Findtomlplusplus.cmake
+++ /dev/null
@@ -1,35 +0,0 @@
-# Findtomlplusplus.cmake
-
-# 首先检查是否已经定义了变量 tomlplusplus_FOUND
-if (tomlplusplus_FOUND)
- return()
-endif()
-
-# 定义 tomldir 用于指定 toml++ 的安装路径
-set(tomldir "" CACHE PATH "Path to the tomlplusplus installation directory")
-
-# 设置默认的库名和头文件路径
-set(tomlplusplus_LIBRARIES "")
-set(tomlplusplus_INCLUDE_DIRS "")
-
-# 检查给定路径是否存在 toml++ 库文件
-find_path(tomlplusplus_INCLUDE_DIRS "toml.hpp" HINTS ${tomldir}/include)
-
-# 如果找到头文件路径,则设置 tomlplusplus_FOUND 为真
-if (tomlplusplus_INCLUDE_DIRS)
- set(tomlplusplus_FOUND TRUE)
-endif()
-
-# 检查给定路径是否存在 toml++ 库文件
-find_library(tomlplusplus_LIBRARIES NAMES tomlplusplus libtomlplusplus HINTS ${tomldir}/lib)
-
-# 如果找到库文件,则设置 tomlplusplus_FOUND 为真
-if (tomlplusplus_LIBRARIES)
- set(tomlplusplus_FOUND TRUE)
-endif()
-
-# 导出结果变量
-if (tomlplusplus_FOUND)
- set(tomlplusplus_INCLUDE_DIRS ${tomlplusplus_INCLUDE_DIRS} CACHE PATH "Path to the tomlplusplus include directory.")
- set(tomlplusplus_LIBRARIES ${tomlplusplus_LIBRARIES} CACHE FILEPATH "Path to the tomlplusplus library.")
-endif()
diff --git a/cmake_modules/ScanModule.cmake b/cmake_modules/ScanModule.cmake
new file mode 100644
index 00000000..8a54b8c6
--- /dev/null
+++ b/cmake_modules/ScanModule.cmake
@@ -0,0 +1,17 @@
+function(scan_and_generate_modules source_dir return_var)
+ set(modules_name_r "")
+ file(GLOB_RECURSE CPP_FILES "${source_dir}/*.cpp")
+ foreach(cpp_file ${CPP_FILES})
+ file(READ ${cpp_file} file_content)
+ string(REGEX MATCH "ATOM_MODULE\\(([a-zA-Z0-9_]+)," match ${file_content})
+ if(match)
+ string(REGEX REPLACE "ATOM_MODULE\\(([a-zA-Z0-9_]+),.*" "\\1" module_name ${match})
+ if(NOT module_name)
+ message(WARNING "Found ATOM_MODULE macro in ${cpp_file} but could not extract module name.")
+ continue()
+ endif()
+ set(modules_name_r ${module_name})
+ endif()
+ endforeach()
+ set(${return_var} "${module_name_r}" PARENT_SCOPE)
+endfunction()
diff --git a/conanfile.py b/conanfile.py
index 99ed9e98..a2462b84 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -14,9 +14,7 @@ class ConanFile(ConanFile):
requires = [
"argparse/3.0",
- "backward-cpp/1.6",
"cpp-httplib/0.15.3",
- "libzippp/7.1-1.10.1",
"openssl/3.2.1",
"zlib/1.3.1",
"oatpp/1.3.0",
@@ -24,11 +22,8 @@ class ConanFile(ConanFile):
"oatpp-openssl/1.3.0",
"oatpp-swagger/1.3.0",
"loguru/cci.20230406",
- "magic_enum/0.9.5",
"cfitsio/4.3.1",
"tinyxml2/10.0.0",
- "pybind11/2.12.0",
- "pybind11_json/0.2.13",
"cpython/3.12.2",
"fmt/10.2.1",
"opencv/4.9.0"
diff --git a/conanfile.txt b/conanfile.txt
index 235be8c4..1d181bcc 100644
--- a/conanfile.txt
+++ b/conanfile.txt
@@ -1,13 +1,10 @@
[requires]
argparse/3.0
-backward-cpp/1.6
cfitsio/4.3.1
cpython/3.12.2
cpp-httplib/0.15.3
fmt/10.2.1
-libzippp/7.1-1.10.1
loguru/cci.20230406
-magic_enum/0.9.5
oatpp/1.3.0
oatpp-websocket/1.3.0
oatpp-openssl/1.3.0
diff --git a/config/template/goto_center.json b/config/template/goto_center.json
index ffb2b3be..f3df6a02 100644
--- a/config/template/goto_center.json
+++ b/config/template/goto_center.json
@@ -1,186 +1,264 @@
{
- "name": "GotoCenter",
- "version": "1.0",
- "author": "Max Qian",
- "type": "group",
- "error": "yes",
- "warning": "yes",
- "tasks": [
- [
- {
- "name": "Goto",
- "type": "action",
- "action": "goto_target",
- "next_step": "CheckCrood",
- "priority": 1,
- "async": false,
- "retry": 1,
- "target_type": "device.telescope",
- "target": "Telescope Simulator",
- "params": {
- "target": "target_name",
- "ra": "xx.xx.xx",
- "dec": "xx.xx.xx",
- "az": "xx.xx.xx",
- "alt": "xx.xx.xx"
- }
+ "name": "GotoCenter",
+ "version": "2.0",
+ "author": "Max Qian",
+ "functions": [
+ {
+ "name": "Goto",
+ "type": "action",
+ "action": "goto_target",
+ "target_type": "device.telescope",
+ "target": "Telescope Simulator",
+ "params": {
+ "target": {
+ "type": "string",
+ "required": true
+ },
+ "ra": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "dec": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "az": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "alt": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ }
+ }
+ },
+ {
+ "name": "CheckCrood",
+ "type": "loop",
+ "loop_iterations": 3,
+ "steps": [
+ {
+ "name": "Exposure",
+ "type": "action",
+ "action": "start_exposure",
+ "target_type": "device.camera",
+ "target": "CCD Simulator",
+ "params": {
+ "exposure": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx"
+ },
+ "is_save": {
+ "type": "boolean",
+ "required": true
+ },
+ "filename": {
+ "type": "string",
+ "required": true,
+ "default": "solve_tmp.fits"
}
- ],
- [
- {
- "name": "CheckCrood",
- "type": "loop",
- "loop_iterations": 3,
- "error": "yes",
- "warning": "yes",
- "loop_steps": [
- {
- "name": "CheckCrood.Exposure",
- "type": "action",
- "action": "start_exposure",
- "next_step": "CheckCrood.Platesolve",
- "priority": 1,
- "async": false,
- "retry": 1,
- "target_type": "device.camera",
- "target": "CCD Simulator",
- "params": {
- "exposure": "xx.xx",
- "is_save": true,
- "filename": "solve_tmp.fits"
- }
- },
- {
- "name": "CheckCrood.Platesolve",
- "type": "condition",
- "action": "palte_solve",
- "next_step": "StartTrack",
- "priority": 1,
- "async": false,
- "retry": 3,
- "result": true,
- "result_name": "solve_result",
- "result_type": "memory",
- "result_template": {
- "ra": {
- "type": "string"
- },
- "dec": {
- "type": "string"
- },
- "ra_error": {
- "type": "string"
- },
- "dec_error": {
- "type": "string"
- },
- "radius": {
- "type": "string"
- }
- },
- "target_type": "device.solver",
- "target": "Astrometry.net OffLine",
- "params": {
- "ra": "xx.xx.xx",
- "dec": "xx.xx.xx",
- "radius": "xx.xx",
- "height": "xx.xx",
- "width": "xx.xx",
- "downsample": 1,
- "timeout": 100,
- "depth": [
- 1,
- 1
- ],
- "filename": "solve_tmp.fits"
- },
- "condition": {
- "ra": "xx.xx.xx",
- "dec": "xx.xx.xx",
- "az": "xx.xx.xx",
- "alt": "xx.xx.xx",
- "radius": "xx.xx"
- },
- "false": [
- {
- "name": "CheckCrood.Calculate",
- "type": "action",
- "action": "calculate_crood",
- "next_step": "CheckCrood.Exposure",
- "priority": 1,
- "async": false,
- "retry": 1,
- "target_type": "lithium.device",
- "target": "",
- "result": true,
- "result_name": "proceed_result",
- "result_type": "memory",
- "result_template": {
- "ra": {
- "type": "string"
- },
- "dec": {
- "type": "string"
- },
- "radius": {
- "type": "string"
- }
- },
- "import_params": "solve_result",
- "params": {
- "ra": "solve_result.ra",
- "dec": "solve_result.dec",
- "radius": "xx.xx"
- }
- },
- {
- "name": "Goto",
- "type": "action",
- "action": "goto_target",
- "next_step": "CheckCrood",
- "priority": 1,
- "async": false,
- "retry": 1,
- "target_type": "device.telescope",
- "target": "Telescope Simulator",
- "result": false,
- "import_params": "proceed_result",
- "params": {
- "target": "target_name",
- "ra": "proceed_result.ra",
- "dec": "proceed_result.dec",
- "az": "proceed_result.az",
- "alt": "proceed_result.alt",
- "radius": "proceed_result.radius"
- }
- }
- ]
- }
- ],
- "loop_error": [
- {
- "name": "GotoCenterError",
- "error": "Failed to goto target center"
- }
- ]
+ }
+ },
+ {
+ "name": "Platesolve",
+ "type": "condition",
+ "action": "palte_solve",
+ "target_type": "device.solver",
+ "target": "Astrometry.net OffLine",
+ "params": {
+ "ra": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "dec": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "radius": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx"
+ },
+ "height": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx"
+ },
+ "width": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx"
+ },
+ "downsample": {
+ "type": "integer",
+ "required": true,
+ "default": 1,
+ "range": [1, 10]
+ },
+ "timeout": {
+ "type": "integer",
+ "required": true,
+ "default": 100,
+ "range": [10, 600]
+ },
+ "depth": {
+ "type": "array",
+ "required": true,
+ "default": [1, 1],
+ "items": {
+ "type": "integer",
+ "range": [1, 10]
+ }
+ },
+ "filename": {
+ "type": "string",
+ "required": true,
+ "default": "solve_tmp.fits"
}
- ],
- [
+ },
+ "condition": {
+ "ra": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "dec": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "az": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "alt": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx.xx"
+ },
+ "radius": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx"
+ }
+ },
+ "true": {
+ "type": "break"
+ },
+ "false": [
+ {
+ "name": "Calculate",
+ "type": "action",
+ "action": "calculate_crood",
+ "target_type": "lithium.device",
+ "params": {
+ "ra": {
+ "type": "string",
+ "required": true,
+ "source": "solve_result.ra"
+ },
+ "dec": {
+ "type": "string",
+ "required": true,
+ "source": "solve_result.dec"
+ },
+ "radius": {
+ "type": "string",
+ "required": true,
+ "format": "xx.xx"
+ }
+ }
+ },
{
- "name": "StartTrack",
- "type": "action",
- "action": "start_track",
- "next_step": "StartTrack",
- "priority": 2,
- "async": true,
- "retry": 1,
- "result": false,
- "target_type": "device.telescope",
- "target": "Telescope Simulator",
- "params": {
- "speed": "star"
+ "name": "Goto",
+ "type": "call",
+ "function": "Goto",
+ "params": {
+ "ra": {
+ "type": "string",
+ "required": true,
+ "source": "proceed_result.ra"
+ },
+ "dec": {
+ "type": "string",
+ "required": true,
+ "source": "proceed_result.dec"
+ },
+ "az": {
+ "type": "string",
+ "required": true,
+ "source": "proceed_result.az"
+ },
+ "alt": {
+ "type": "string",
+ "required": true,
+ "source": "proceed_result.alt"
+ },
+ "radius": {
+ "type": "string",
+ "required": true,
+ "source": "proceed_result.radius"
}
+ }
}
- ]
- ]
+ ]
+ }
+ ],
+ "error": "Failed to goto target center"
+ },
+ {
+ "name": "StartTrack",
+ "type": "action",
+ "action": "start_track",
+ "target_type": "device.telescope",
+ "target": "Telescope Simulator",
+ "params": {
+ "speed": {
+ "type": "string",
+ "required": true,
+ "default": "star",
+ "enum": ["star", "lunar", "solar"]
+ }
+ }
+ }
+ ],
+ "steps": [
+ {
+ "name": "Goto",
+ "type": "call",
+ "function": "Goto",
+ "params": {
+ "target": "M42",
+ "ra": "05:35:17.3",
+ "dec": "-05:23:28",
+ "az": "180:00:00",
+ "alt": "60:00:00"
+ }
+ },
+ {
+ "name": "CheckCrood",
+ "type": "call",
+ "function": "CheckCrood",
+ "params": {
+ "loop_iterations": 5
+ }
+ },
+ {
+ "name": "StartTrack",
+ "type": "call",
+ "function": "StartTrack",
+ "async": true,
+ "params": {
+ "speed": "star"
+ }
+ }
+ ]
}
diff --git a/doc/asyncapi.json b/doc/asyncapi.json
deleted file mode 100644
index d9389b97..00000000
--- a/doc/asyncapi.json
+++ /dev/null
@@ -1,298 +0,0 @@
-{
- "asyncapi": "2.6.0",
- "info": {
- "title": "Lithium Server API",
- "version": "1.0.0",
- "description": "An open and light astrophotography terminal like lithium",
- "license": {
- "name": "GNU GENERAL PUBLIC LICENSE, Version 3",
- "url": "https://www.gnu.org/licenses/gpl-3.0.en.html"
- }
- },
- "servers": {
- "main": {
- "url": "http://127.0.0.1:8000",
- "protocol": "websocket",
- "description": "Main websocket server"
- }
- },
- "channels": {
- "GetDeviceList": {
- "publish": {
- "operationId": "GetDeviceList",
- "message": {
- "name": "GetDeviceList",
- "payload": {
- "type": "object",
- "properties": {
- "device_type": {
- "type": "string",
- "description": "Type of device to retrieve the list"
- }
- },
- "required": [
- "device_type"
- ]
- }
- }
- }
- },
- "AddDevice": {
- "publish": {
- "operationId": "AddDevice",
- "message": {
- "name": "AddDevice",
- "payload": {
- "type": "object",
- "properties": {
- "device_type": {
- "type": "string",
- "description": "Type of device to add"
- },
- "device_name": {
- "type": "string",
- "description": "Name of device to add"
- },
- "lib_name": {
- "type": "string",
- "description": "Name of library to load device"
- }
- },
- "required": [
- "device_name",
- "device_type"
- ]
- }
- }
- }
- },
- "AddDeviceLibrary": {
- "publish": {
- "operationId": "AddDeviceLibrary",
- "message": {
- "name": "AddDeviceLibrary",
- "payload": {
- "type": "object",
- "properties": {
- "lib_path": {
- "type": "string",
- "description": "Path of device library to add"
- },
- "lib_name": {
- "type": "string",
- "description": "Name of device library to add"
- }
- },
- "required": [
- "lib_name",
- "lib_path"
- ]
- }
- }
- }
- },
- "RemoveDevice": {
- "publish": {
- "operationId": "RemoveDevice",
- "message": {
- "name": "RemoveDevice",
- "payload": {
- "type": "object",
- "properties": {
- "device_type": {
- "type": "string",
- "description": "Type of device to remove"
- },
- "device_name": {
- "type": "string",
- "description": "Name of device to remove"
- }
- },
- "required": [
- "device_name",
- "device_type"
- ]
- }
- }
- }
- },
- "RemoveDevicesByName": {
- "publish": {
- "operationId": "RemoveDevicesByName",
- "message": {
- "name": "RemoveDevicesByName",
- "payload": {
- "type": "object",
- "properties": {
- "device_name": {
- "type": "string",
- "description": "Name of device to remove"
- }
- },
- "required": [
- "device_name"
- ]
- }
- }
- }
- },
- "RemoveDeviceLibrary": {
- "publish": {
- "operationId": "RemoveDeviceLibrary",
- "message": {
- "name": "RemoveDeviceLibrary",
- "payload": {
- "type": "object",
- "properties": {
- "lib_name": {
- "type": "string",
- "description": "Name of device library to remove"
- }
- },
- "required": [
- "lib_name"
- ]
- }
- }
- }
- },
- "RunDeviceTask": {
- "publish": {
- "operationId": "RunDeviceTask",
- "message": {
- "name": "RunDeviceTask",
- "payload": {
- "type": "object",
- "properties": {
- "device_name": {
- "type": "string"
- },
- "device_uuid": {
- "type": "string"
- },
- "device_type": {
- "type": "string"
- },
- "task_name": {
- "type": "string"
- }
- },
- "required": [
- "device_type",
- "task_name"
- ]
- }
- }
- }
- },
- "CreateProcess": {
- "publish": {
- "operationId": "CreateProcess",
- "message": {
- "name": "CreateProcess",
- "title": "Create a Process",
- "contentType" :"application/json",
- "summary":"Create a alone process to run system command (depend on platform)",
- "payload": {
- "type": "object",
- "properties": {
- "command": {
- "type": "string"
- },
- "cmd_id": {
- "type": "string"
- }
- },
- "required": [
- "command",
- "cmd_id"
- ]
- }
- }
- }
- },
- "RunScript": {
- "publish": {
- "operationId": "RunScript",
- "message": {
- "name": "RunScript",
- "title": "Run a script",
- "contentType" :"application/json",
- "summary":"Create a alone process to run shell script (depend on platform)",
- "payload": {
- "type": "object",
- "properties": {
- "script_name": {
- "type": "string",
- "description": "Name of script to run"
- },
- "script_id": {
- "type": "string",
- "description": "ID of script to run , required in TerminateProcessByName"
- }
- },
- "required": [
- "script_name",
- "script_id"
- ]
- }
- }
- }
- },
- "TerminateProcessByName": {
- "publish": {
- "operationId": "TerminateProcessByName",
- "message": {
- "name": "TerminateProcessByName",
- "title": "Terminate an exists process",
- "contentType" :"application/json",
- "summary":"Terminate an existed process created by ProcessManager.Can not operate with other software",
- "payload": {
- "type": "object",
- "properties": {
- "process_name": {
- "type": "string",
- "description": "Name of process to terminate"
- }
- },
- "required": [
- "process_name"
- ]
- }
- }
- }
- },
- "GetRunningProcesses": {
- "publish": {
- "operationId": "GetRunningProcesses",
- "message": {
- "name": "GetRunningProcesses",
- "title": "Get current running processes",
- "contentType" :"application/json",
- "summary":"获取当前正在运行的所有进程的信息(只包含由ProcessManager创建的,不能获取系统进程,如有需要请调用其他的API)",
- "payload": {}
- }
- }
- },
- "GetProcessOutput": {
- "publish": {
- "operationId": "GetProcessOutput",
- "message": {
- "name": "GetProcessOutput",
- "payload": {
- "type": "object",
- "properties": {
- "process_name": {
- "type": "string",
- "description": "Name of process to get output"
- }
- },
- "required": [
- "process_name"
- ]
- }
- }
- }
- }
- }
-}
diff --git a/doc/atom/algorithm/algorithm_zh.md b/doc/atom/algorithm/algorithm_zh.md
new file mode 100644
index 00000000..a13a8202
--- /dev/null
+++ b/doc/atom/algorithm/algorithm_zh.md
@@ -0,0 +1,198 @@
+# 算法库文档
+
+## 概述
+
+该库是一个 C++实现的算法集合,包括 Knuth-Morris-Pratt (KMP)字符串搜索算法、Boyer-Moore 字符串搜索算法和一个通用的布隆过滤器(Bloom Filter)数据结构。
+
+## 命名空间
+
+### `atom::algorithm`
+
+此命名空间包含了库中提供的所有算法实现的类和函数。
+
+## 类
+
+### `KMP`
+
+实现了 Knuth-Morris-Pratt (KMP)字符串搜索算法。
+
+#### 构造函数
+
+- `explicit KMP(std::string_view pattern)`
+
+ 使用给定的模式构造一个`KMP`对象。
+
+ **参数:**
+
+ - `pattern` - 要在文本中搜索的模式。
+
+#### 公共方法
+
+- `[[nodiscard]] auto search(std::string_view text) const -> std::vector`
+
+ 使用 KMP 算法在给定文本中搜索模式的出现位置。
+
+ **参数:**
+
+ - `text` - 要搜索的文本。
+
+ **返回:**
+
+ - `std::vector` - 包含模式在文本中起始位置的向量。
+
+- `void setPattern(std::string_view pattern)`
+
+ 设置新的搜索模式。
+
+ **参数:**
+
+ - `pattern` - 要搜索的新模式。
+
+#### 私有方法
+
+- `auto computeFailureFunction(std::string_view pattern) -> std::vector`
+
+ 计算给定模式的失败函数(部分匹配表)。
+
+ **参数:**
+
+ - `pattern` - 要计算失败函数的模式。
+
+ **返回:**
+
+ - `std::vector` - 计算出的失败函数(部分匹配表)。
+
+#### 数据成员
+
+- `std::string pattern_`
+
+ 要搜索的模式。
+
+- `std::vector failure_`
+
+ 模式的失败函数(部分匹配表)。
+
+### `BloomFilter`
+
+实现了布隆过滤器(Bloom Filter)数据结构。
+
+#### 模板参数
+
+- `N` - 布隆过滤器的大小(位数)。
+
+#### 构造函数
+
+- `explicit BloomFilter(std::size_t num_hash_functions)`
+
+ 使用指定数量的哈希函数构造一个新的`BloomFilter`对象。
+
+ **参数:**
+
+ - `num_hash_functions` - 用于布隆过滤器的哈希函数数量。
+
+#### 公共方法
+
+- `void insert(std::string_view element)`
+
+ 将一个元素插入到布隆过滤器中。
+
+ **参数:**
+
+ - `element` - 要插入的元素。
+
+- `[[nodiscard]] auto contains(std::string_view element) const -> bool`
+
+ 检查布隆过滤器中是否可能包含某个元素。
+
+ **参数:**
+
+ - `element` - 要检查的元素。
+
+ **返回:**
+
+ - `bool` - 如果元素可能存在则返回`true`,否则返回`false`。
+
+#### 私有方法
+
+- `auto hash(std::string_view element, std::size_t seed) const -> std::size_t`
+
+ 使用特定的种子计算元素的哈希值。
+
+ **参数:**
+
+ - `element` - 要哈希的元素。
+ - `seed` - 哈希函数的种子值。
+
+ **返回:**
+
+ - `std::size_t` - 元素的哈希值。
+
+#### 数据成员
+
+- `std::bitset m_bits_`
+
+ 代表布隆过滤器的位集。
+
+- `std::size_t m_num_hash_functions_`
+
+ 使用的哈希函数数量。
+
+### `BoyerMoore`
+
+实现了 Boyer-Moore 字符串搜索算法。
+
+#### 构造函数
+
+- `explicit BoyerMoore(std::string_view pattern)`
+
+ 使用给定的模式构造一个`BoyerMoore`对象。
+
+ **参数:**
+
+ - `pattern` - 要在文本中搜索的模式。
+
+#### 公共方法
+
+- `auto search(std::string_view text) const -> std::vector`
+
+ 使用 Boyer-Moore 算法在给定文本中搜索模式的出现位置。
+
+ **参数:**
+
+ - `text` - 要搜索的文本。
+
+ **返回:**
+
+ - `std::vector` - 包含模式在文本中起始位置的向量。
+
+- `void setPattern(std::string_view pattern)`
+
+ 设置新的搜索模式。
+
+ **参数:**
+
+ - `pattern` - 要搜索的新模式。
+
+#### 私有方法
+
+- `void computeBadCharacterShift()`
+
+ 计算当前模式的坏字符偏移表。
+
+- `void computeGoodSuffixShift()`
+
+ 计算当前模式的好后缀偏移表。
+
+#### 数据成员
+
+- `std::string pattern_`
+
+ 要搜索的模式。
+
+- `std::unordered_map bad_char_shift_`
+
+ 坏字符偏移表。
+
+- `std::vector good_suffix_shift_`
+
+ 好后缀偏移表。
diff --git a/doc/components/README_ZH.md b/doc/components/README_ZH.md
index f1f00128..cf6c317e 100644
--- a/doc/components/README_ZH.md
+++ b/doc/components/README_ZH.md
@@ -1,125 +1,130 @@
# Lithium & Atom Components
-Atom 的组件机制是元素天文所有组建的基础,正如其名,组件是最基础的,你可以通过组件增强服务器的功能。
+Atom的组件机制是元素天文所有组件的基础,正如其名,组件是最基础的,是一切功能的核心,通过组件可以个性化扩展服务器功能。
## 加载机制
-由于 c++的特殊性,导致无法像 java 那样通过类名加载类,所以组件的加载机制是通过加载动态库后获取对应的共享类指针完成的
+由于C++的特殊性,无法像Java那样通过类名加载类,更加不能像python那样导入文件即可。目前采用的组件加载机制是加载动态库后获取指定共享类指针。
## 组件组成
-每个组件都是有动态库和对应的 package.json 组成的,如果后需要有需要的话,可以加入 package.xml 之类的文件来描述组件的依赖关系。
+每个组件由动态库和对应的`package.json`组成,如果需要的话,可以加入`package.xml`等文件来描述组件的依赖关系。
+
+> [!IMPORTANT]
+> 优先支持`package.json`,不一定会兼容xml格式
举一个例子:
+> [!NOTE]
+> 一个文件夹中可以有多个不同名称的动态,只需要在`package.json`中指定即可
+
```txt
component-demo
├── package.json
└── component-demo.so
+ └── component-demo-2.so
```
-在这个例子中,我们的 component-demo 组件中包含一个 component-demo.so(可以与文件夹名称不同,而且后缀名根据平台而定)动态库,以及 package.json 文件。
+在这个例子中,`component-demo`组件包含一个或多个动态库(后缀名根据平台而定,__需要特别注意的是,Mingw64环境需要使用so作为后缀,虽然也是Windows环境__)和`package.json`文件。
### package.json
-package.json 是组件的配置文件,它包含了组件的基本信息,比如组件的名称,版本,作者等。
+`package.json`是组件的配置文件,包含组件的基本信息,比如组件的名称、版本、作者等。
```json
{
- "name": "example",
- "version": "0.0.0",
- "type": "shared",
- "description": "An example project",
- "license": "LGPL-3.0-or-later",
- "author": "Max Qian",
- "repository": {
- "type": "git",
- "url": "https://github.com/maxqian/cobalt-example.git"
- },
- "bugs": {
- "url": "https://github.com/maxqian/cobalt-example/issues"
- },
- "homepage": "https://github.com/maxqian/cobalt-example",
- "keywords": ["atom", "example", "component"],
- "scripts": {
- "dev": "run"
- },
- "dependencies": ["atom.core"],
- "main": {
- "example1": {
- "func": "getExample1",
- "type": "shared"
- }
- }
+ "name": "atom.io",
+ "version": "1.0.0",
+ "type": "shared",
+ "description": "Atom IO Module",
+ "license": "GPL-3.0-or-later",
+ "author": "Max Qian",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ElementAstro/Lithium"
+ },
+ "bugs": {
+ "type": "git",
+ "url": "https://github.com/ElementAstro/Lithium/issues"
+ },
+ "homepage": {
+ "type": "git",
+ "url": "https://github.com/ElementAstro/Lithium"
+ },
+ "keywords": [
+ "lithium",
+ "config"
+ ],
+ "scripts": {
+ "build": "cmake --build-type=Release -- -j 4",
+ "lint": "clang-format -i src/*.cpp src/*.h"
+ },
+ "modules": [
+ {
+ "name": "io",
+ "entry": "getInstance"
+ }
+ ]
}
+
```
-其中`main`是最为重要的部分,它定义了组件的入口函数,以及组件的类型,目前支持`shared` 、 `inject`、`alone`、`executable`四种类型。
++ `type`声明组件类型,分为`shared`和`standalone`两种,`shared`表示共享组件,`standalone`表示独立组件,加载机制完全不同!
++ `scripts`是脚本,用于构建和格式化代码。
++ `modules`是一个json数组,其中包括若干组件信息,包括组件的名称(是注册在模块管理器中的名称)、和入口函数(需要与动态中完全相同,可以是C++翻译之后的名称)。
-Warning: 每种组件的加载机制不太一样,请注意区分。
+__Warning__: 整个`package.json`文件必须包含`modules`字段,否则无法正常加载。
### 动态库
-动态库的加载具体加载逻辑请参考`atom/module/module_loader.cpp`,在 Windows 下平台我们使用了`dl-win`库,因此函数形式与 Linux 下一致。
+加载逻辑请参考`atom/module/module_loader.cpp`,在Windows平台我们使用了`dl-win`库(后续会添加Windows原生API的支持),因此函数形式与Linux下保持一致。
-你可以自己写一个小函数进行测试,后续也会提供对应的构建工具
+你可以自己写一个小函数进行测试,后续也会提供对应的构建工具。
```cpp
-#include
+// example.cpp
#include
-int main()
-{
- void* handle = dlopen("./component-demo.so", RTLD_LAZY);
- if (handle == nullptr)
- {
- std::cout << dlerror() << std::endl;
- return -1;
+// 这个函数将被导出到动态库
+extern "C" void helloWorld() {
+ std::cout << "Hello, World!" << std::endl;
+}
+
+// 这个类将不会被导出,因为它是C++特定的
+class MyClass {
+public:
+ void sayHello() {
+ std::cout << "MyClass says hello!" << std::endl;
}
+};
- return 0;
+// 这个函数将被导出,它将创建一个MyClass的实例并调用其sayHello方法
+extern "C" void callMyClass() {
+ MyClass myObj;
+ myObj.sayHello();
}
```
-动态库中必须要存在 package.json 中声明的函数,否则将无法正常加载。
-
## 组件注册
-组件的注册与管理使用`ComponentManager`完成,下面是 Lithium 服务器中组件管理的目录架构
+组件的注册与管理使用`ComponentManager`完成,下面是Lithium服务器中组件管理的目录架构:
```txt
components
- ├── component-finder.cpp
- ├── component_finder.hpp
- ├── component_info.cpp
- ├── component_info.hpp
- ├── component_manager.cpp
- ├── component_manager.hpp
- ├── package_manager.cpp
- └── package_manager.hpp
- ├── project_info.cpp
- └── project_info.hpp
- ├── project_manager.cpp
- └── project_manager.hpp
- ├── sanbox.cpp
- └── sanbox.hpp
+ ├── addons.cpp
+ ├── addons.hpp
+ ├── compiler.cpp
+ ├── compiler.hpp
+ ├── component.hpp
+ ├── dependency.cpp
+ ├── dependency.hpp
+ ├── loader.cpp
+ ├── loader.hpp
+ ├── manager.cpp
+ ├── manager.hpp
+ ├── module.cpp
+ ├── sandbox.cpp
+ ├── sandbox.hpp
+ ├── sort.cpp
+ ├── sort.hpp
```
-
-其中每个组件的功能:
-`component-finder`是组件的查找器,主要负责遍历`modules`目录下所有符合条件的文件夹,具体的条件为存在至少一个动态库和 package.json 文件
-`component_info`是组件信息的定义,主要用来处理 package.json 中的组件信息
-`component_manager`是组件管理器,主要用来管理组件的加载和卸载
-`package_manager`是包管理器,主要用来管理组件的包
-`project_info`是项目信息的定义,主要用来组件之间的依赖关系和防止循环引用
-`project_manager`是项目管理器,主要用来管理项目的加载和卸载,可以更加方便的更新组件,提供 Git 项目管理和基础的 CI 构建机制
-`sanbox`是沙盒,主要用来隔离组件的运行环境,创建`独立组件`的安全运行环境,在 Linux 下的运行效果较好
-
-### 设备组件
-
-设备组件不同于普通的组件,它的交互机制类似于 INDI,但是协议更加简单,后续会单独作为 atom.driver 驱动库进行实现。
-
-## 组件通信
-
-### 共享组件
-
-共享组件间的通信是使用`MessageBus(Global)`实现的
diff --git a/doc/device/ascom_switch.md b/doc/device/ascom_switch.md
new file mode 100644
index 00000000..48352622
--- /dev/null
+++ b/doc/device/ascom_switch.md
@@ -0,0 +1,84 @@
+# AscomSwitch
+
+The `AscomSwitch` class is part of the `NINA.Equipment.Equipment.MySwitch.Ascom` namespace and is used to interact with ASCOM switch devices.
+
+## Namespace
+
+```csharp
+namespace NINA.Equipment.Equipment.MySwitch.Ascom
+```
+
+## Class Declaration
+
+```csharp
+internal class AscomSwitch : BaseINPC, ISwitch
+```
+
+## Properties
+
+### `Id`
+
+- **Type:** `short`
+- **Description:** The unique identifier for the switch.
+
+### `Name`
+
+- **Type:** `string`
+- **Description:** The name of the switch.
+- **Property Change Notification:** Uses `RaisePropertyChanged` when updated.
+
+### `Description`
+
+- **Type:** `string`
+- **Description:** A description of the switch.
+
+### `Value`
+
+- **Type:** `double`
+- **Description:** The current value of the switch.
+- **Property Change Notification:** Uses `RaisePropertyChanged` when updated.
+
+## Constructors
+
+### `AscomSwitch`
+
+```csharp
+public AscomSwitch(ISwitchV2 s, short id)
+```
+
+- **Parameters:**
+ - `s`: An instance of `ISwitchV2` representing the ASCOM switch hub.
+ - `id`: The unique identifier for the switch.
+- **Description:** Initializes the `AscomSwitch` instance with the provided switch hub and identifier. Retrieves initial values for `Name`, `Description`, and `Value`.
+
+## Methods
+
+### `Poll`
+
+```csharp
+public async Task Poll()
+```
+
+- **Description:** Polls the switch for updated values.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Poll Method] --> B[Start Task]
+ B --> C[Try to Retrieve Name and Value]
+ C -- Success --> D[Update Name and Value]
+ C -- Failure --> E[Log Failure]
+ D --> F[Raise PropertyChanged]
+ E --> F
+ F --> G[Return Success]
+ G --> H[End]
+```
+
+**Detailed Steps:**
+
+1. **Start Task:** Begins an asynchronous task to retrieve the switch values.
+2. **Try to Retrieve Name and Value:** Attempts to get the `Name` and `Value` from the switch hub.
+ - **Success:** Updates the `Name` and `Value` properties and logs the retrieved values.
+ - **Failure:** Logs a failure message.
+3. **Raise PropertyChanged:** Notifies that the properties have changed if retrieval was successful.
+4. **Return Success:** Returns a boolean indicating whether the operation was successful.
diff --git a/doc/device/ascom_switch_hub.md b/doc/device/ascom_switch_hub.md
new file mode 100644
index 00000000..58e364ba
--- /dev/null
+++ b/doc/device/ascom_switch_hub.md
@@ -0,0 +1,156 @@
+# AscomSwitchHub
+
+The `AscomSwitchHub` class is part of the `NINA.Equipment.Equipment.MySwitch.Ascom` namespace and manages a collection of ASCOM switches. It extends `AscomDevice` and implements `ISwitchHub`, providing functionality to discover and interact with ASCOM switch devices.
+
+## Namespace
+
+```csharp
+namespace NINA.Equipment.Equipment.MySwitch.Ascom
+```
+
+## Class Declaration
+
+```csharp
+public partial class AscomSwitchHub : AscomDevice, ISwitchHub, IDisposable
+```
+
+## Properties
+
+### `Switches`
+
+- **Type:** `ICollection`
+- **Description:** A collection of switches managed by the hub.
+- **Property Change Notification:** Uses `ObservableProperty` for automatic property change notification.
+
+## Constructors
+
+### `AscomSwitchHub(string id, string name)`
+
+```csharp
+public AscomSwitchHub(string id, string name) : base(id, name)
+```
+
+- **Parameters:**
+ - `id`: The identifier for the switch hub.
+ - `name`: The name of the switch hub.
+- **Description:** Initializes a new instance of the `AscomSwitchHub` class with the specified ID and name. Initializes an empty collection of switches.
+
+### `AscomSwitchHub(AscomDevice deviceMeta)`
+
+```csharp
+public AscomSwitchHub(AscomDevice deviceMeta) : base(deviceMeta)
+```
+
+- **Parameters:**
+ - `deviceMeta`: Metadata for the ASCOM device.
+- **Description:** Initializes a new instance using the metadata from an `AscomDevice`. Initializes an empty collection of switches.
+
+## Methods
+
+### `ScanForSwitches`
+
+```csharp
+private async Task ScanForSwitches()
+```
+
+- **Description:** Scans for switches connected to the ASCOM switch hub and adds them to the `Switches` collection.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Start ScanForSwitches] --> B[Get MaxSwitch Count]
+ B --> C[Loop through Switch Indices]
+ C --> D[Try to Get Switch]
+ D --> E[If CanWrite]
+ E -- Yes --> F[Create AscomWritableSwitch]
+ E -- No --> G[Create AscomSwitch]
+ F --> H[Add to Switches]
+ G --> H
+ D -- Exception --> I[Handle Exception]
+ I --> J[Try AscomWritableV1Switch]
+ J --> K[Add to Switches]
+ I -- Failure --> L[Create AscomV1Switch]
+ L --> K
+ K --> M[End]
+```
+
+**Detailed Steps:**
+
+1. **Start ScanForSwitches:** Begins scanning for connected switches.
+2. **Get MaxSwitch Count:** Retrieves the maximum number of switches from the device.
+3. **Loop through Switch Indices:** Iterates through each switch index.
+4. **Try to Get Switch:** Attempts to create a switch object for the given index.
+ - **If CanWrite:**
+ - **Yes:** Creates an `AscomWritableSwitch` and adds it to the `Switches` collection.
+ - **No:** Creates an `AscomSwitch` and adds it to the `Switches` collection.
+ - **Exception Handling:**
+ - **Handle Exception:** Catches `MethodNotImplementedException` and tries to create an `AscomWritableV1Switch`. If this fails, creates an `AscomV1Switch`.
+
+### `PostConnect`
+
+```csharp
+protected override async Task PostConnect()
+```
+
+- **Description:** Performs actions after establishing a connection, such as scanning for switches.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[PostConnect] --> B[Call ScanForSwitches]
+ B --> C[End]
+```
+
+**Detailed Steps:**
+
+1. **Call ScanForSwitches:** Initiates the scanning process to discover switches.
+2. **End:** Completes the connection post-setup.
+
+### `PostDisconnect`
+
+```csharp
+protected override void PostDisconnect()
+```
+
+- **Description:** Performs actions after disconnecting, such as clearing the collection of switches.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[PostDisconnect] --> B[Clear Switches Collection]
+ B --> C[End]
+```
+
+**Detailed Steps:**
+
+1. **Clear Switches Collection:** Resets the `Switches` collection to an empty state.
+2. **End:** Completes the disconnection process.
+
+### `GetInstance`
+
+```csharp
+protected override ISwitchV2 GetInstance()
+```
+
+- **Description:** Provides an instance of `ISwitchV2` for the switch hub.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[GetInstance] --> B[Check deviceMeta]
+ B -- Null --> C[Create Default Switch]
+ B -- Not Null --> D[Create AlpacaSwitch]
+ C --> E[Return Switch]
+ D --> E
+ E --> F[End]
+```
+
+**Detailed Steps:**
+
+1. **Check deviceMeta:** Determines whether `deviceMeta` is null.
+ - **Null:** Creates a default `Switch` instance.
+ - **Not Null:** Creates an `AlpacaSwitch` instance based on the metadata.
+2. **Return Switch:** Returns the created switch instance.
+3. **End:** Completes the instance retrieval process.
diff --git a/doc/device/ascom_switch_v1.md b/doc/device/ascom_switch_v1.md
new file mode 100644
index 00000000..1f82f94a
--- /dev/null
+++ b/doc/device/ascom_switch_v1.md
@@ -0,0 +1,84 @@
+# AscomV1Switch
+
+The `AscomV1Switch` class is part of the `NINA.Equipment.Equipment.MySwitch.Ascom` namespace and implements the `ISwitch` interface. It provides functionality for handling ASCOM V1 switches, including retrieving their values and updating the state.
+
+## Namespace
+
+```csharp
+namespace NINA.Equipment.Equipment.MySwitch.Ascom
+```
+
+## Class Declaration
+
+```csharp
+internal class AscomV1Switch : BaseINPC, ISwitch
+```
+
+## Constructors
+
+### `AscomV1Switch(ISwitchV2 s, short id)`
+
+```csharp
+public AscomV1Switch(ISwitchV2 s, short id)
+```
+
+- **Parameters:**
+ - `s`: The ASCOM switch hub instance.
+ - `id`: The identifier for the switch.
+- **Description:** Initializes a new instance of the `AscomV1Switch` class with the specified switch hub and ID. Sets the initial properties of the switch.
+
+## Properties
+
+### `Id`
+
+- **Type:** `short`
+- **Description:** The identifier for the switch.
+
+### `Name`
+
+- **Type:** `string`
+- **Description:** The name of the switch.
+
+### `Description`
+
+- **Type:** `string`
+- **Description:** The description of the switch.
+
+### `Value`
+
+- **Type:** `double`
+- **Description:** The value of the switch (0 or 1).
+
+## Methods
+
+### `Poll`
+
+```csharp
+public async Task Poll()
+```
+
+- **Description:** Retrieves the current value of the switch asynchronously and updates the `Value` property. Logs the operation and handles exceptions.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Poll] --> B[Run Task]
+ B --> C[Try to Retrieve Value]
+ C --> D[Update Value]
+ D --> E[Log Success]
+ C -- Exception --> F[Log Failure]
+ E --> G[Raise PropertyChanged]
+ F --> G
+ G --> H[Return Success]
+```
+
+**Detailed Steps:**
+
+1. **Run Task:** Executes the value retrieval in a separate task.
+2. **Try to Retrieve Value:** Attempts to get the switch value from the ASCOM switch hub.
+ - **Update Value:** Sets the `Value` property based on the retrieved switch state.
+ - **Log Success:** Logs the successful retrieval of the switch value.
+ - **Exception Handling:** Logs the failure if an exception occurs.
+3. **Raise PropertyChanged:** Notifies any listeners that the `Value` property has changed.
+4. **Return Success:** Returns whether the operation was successful.
diff --git a/doc/device/camera.drawio b/doc/device/camera.drawio
new file mode 100644
index 00000000..59b22f54
--- /dev/null
+++ b/doc/device/camera.drawio
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/device/connect.drawio b/doc/device/connect.drawio
new file mode 100644
index 00000000..a6aabb32
--- /dev/null
+++ b/doc/device/connect.drawio
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/device/connect.md b/doc/device/connect.md
new file mode 100644
index 00000000..b98082ee
--- /dev/null
+++ b/doc/device/connect.md
@@ -0,0 +1,53 @@
+# 连接流程
+
+```mermaid
+graph TD
+ A[第一次设备连接顺序] --> B[启动INDI服务器]
+ B --> C{检查端口是否被占用}
+ C -->|未被占用| D[获取所有可用设备大类,扫描指定目录下的xml文件]
+ D -->|成功| E[通过fifo通知INDI启动指定大类设备]
+ E --> F[通过indi_getprop获取所有可以使用的设备]
+ F --> G[通过indi_setprop设置所有选中设备,并且记录到设备列表中]
+ G --> H[启动成功]
+
+ C -->|被占用| I{查找进程,判断是否为INDI服务器}
+ I -->|是| J[直接杀死]
+ J --> K[再次尝试]
+ K -->|成功| D
+ I -->|否| L[启动失败]
+
+ K --> M[启动失败]
+ D -->|失败| N[启动失败]
+ F --> O[进程监视启动]
+ G --> P[记录用户选择具体设备]
+ P --> Q[推送前端,等待用户选择]
+ Q --> R[推送前端,等待用户选择]
+
+ I -.-> S[启动失败] -->|包括但不限于找不到xml文件,解析错误,版本错误| N
+ C -.-> T[检查fifo管道文件是否创建,是否有缓存]
+ I -.-> U[此处如果为INDI服务器,可以放心杀死,INDI会处理设备断开连接问题] --> L
+ F -.-> V[后续步骤出错概率较小,可以暂时不做异常处理] --> R
+ Q -.-> W[这里直接在大类驱动中添加] --> P
+```
+
+```mermaid
+graph TD
+ A[设备连接流程] --> B[启动INDI服务器]
+ B --> C{端口是否被占用?}
+ C -->|否| D[获取设备列表并扫描xml文件]
+ D -->|成功| E[推送设备类别至前端]
+ E --> F[通过fifo启动选定设备]
+ F --> G[获取所有可用设备并推送前端]
+ G --> H[通过indi_setprop配置设备并记录]
+ H --> I[启动成功]
+
+ C -->|是| J{是否为INDI服务器?}
+ J -->|是| K[杀死进程并重试]
+ K --> L[获取设备列表并扫描xml文件]
+ L -->|失败| M[集中错误处理模块]
+
+ J -->|否| M[集中错误处理模块]
+
+ L -->|成功| E
+ M --> N[记录错误并通知用户]
+```
diff --git a/doc/device/switch_chooser_vm.md b/doc/device/switch_chooser_vm.md
new file mode 100644
index 00000000..29ab595b
--- /dev/null
+++ b/doc/device/switch_chooser_vm.md
@@ -0,0 +1,127 @@
+# SwitchChooserVM
+
+## Overview
+
+The `SwitchChooserVM` class is responsible for choosing and managing switch devices within the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application. It inherits from `DeviceChooserVM` and provides functionality to retrieve a list of switch hubs from various sources, including plugins, ASCOM, and Alpaca.
+
+### Overall Flowchart
+
+```mermaid
+graph TD
+ A[Start] --> B[Get Equipment]
+ B --> C{Retrieve Devices}
+ C -->|Dummy Device| D[Add Dummy Device]
+ C -->|Plugin Providers| E[Retrieve Plugin Devices]
+ E --> F[Add Plugin Devices]
+ C -->|ASCOM| G[Retrieve ASCOM Devices]
+ G --> H[Add ASCOM Devices]
+ C -->|Alpaca| I[Retrieve Alpaca Devices]
+ I --> J[Add Alpaca Devices]
+ D --> K[Determine Selected Device]
+ F --> K
+ H --> K
+ J --> K
+ K --> L[End]
+```
+
+### Step-by-Step Flowcharts
+
+#### 1. Get Equipment Method
+
+The `GetEquipment` method retrieves the list of switch devices from multiple sources and determines the selected device.
+
+```mermaid
+flowchart TD
+ A[Start] --> B[Acquire Lock]
+ B --> C[Initialize Device List]
+ C --> D[Add Dummy Device]
+ D --> E[Retrieve Plugin Devices]
+ E --> F[Add Plugin Devices]
+ F --> G[Retrieve ASCOM Devices]
+ G --> H[Add ASCOM Devices]
+ H --> I[Retrieve Alpaca Devices]
+ I --> J[Add Alpaca Devices]
+ J --> K[Determine Selected Device]
+ K --> L[Release Lock]
+ L --> M[End]
+
+ E -->|For Each Provider| N[Try-Catch]
+ G --> O[Try-Catch]
+ I --> P[Try-Catch]
+```
+
+#### Detailed Steps for Get Equipment
+
+1. **Acquire Lock**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Lock Object]
+ B --> C[Lock Acquired]
+ C --> D[Proceed]
+ ```
+
+2. **Initialize Device List**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Create List of Devices]
+ B --> C[Add Dummy Device]
+ C --> D[Proceed]
+ ```
+
+3. **Retrieve Plugin Devices**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Get Providers]
+ B --> C[Retrieve Devices]
+ C --> D{Error Occurred?}
+ D -->|No| E[Add Devices to List]
+ D -->|Yes| F[Log Error]
+ E --> G[Proceed]
+ F --> G
+ ```
+
+4. **Retrieve ASCOM Devices**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Create ASCOM Interaction]
+ B --> C[Retrieve Switches]
+ C --> D{Error Occurred?}
+ D -->|No| E[Add Devices to List]
+ D -->|Yes| F[Log Error]
+ E --> G[Proceed]
+ F --> G
+ ```
+
+5. **Retrieve Alpaca Devices**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Create Alpaca Interaction]
+ B --> C[Retrieve Switches]
+ C --> D{Error Occurred?}
+ D -->|No| E[Add Devices to List]
+ D -->|Yes| F[Log Error]
+ E --> G[Proceed]
+ F --> G
+ ```
+
+6. **Determine Selected Device**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Determine Device]
+ B --> C[Set Selected Device]
+ C --> D[End]
+ ```
+
+7. **Release Lock**
+
+ ```mermaid
+ flowchart TD
+ A[Start] --> B[Release Lock]
+ B --> C[End]
+ ```
diff --git a/doc/device/switch_vm.md b/doc/device/switch_vm.md
new file mode 100644
index 00000000..0f284502
--- /dev/null
+++ b/doc/device/switch_vm.md
@@ -0,0 +1,107 @@
+# SwitchVM
+
+## Overview
+
+The `SwitchVM` class is a ViewModel for handling switch equipment in the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application. It manages the connection to switch devices, provides commands for interaction, and updates the state of switches.
+
+### Overall Flowchart
+
+```mermaid
+graph TD
+ A[User Interaction] --> B[Execute Command]
+ B --> C{Command Type}
+ C -->|Connect| D[Connect Method]
+ C -->|Disconnect| E[Disconnect Method]
+ C -->|SetSwitchValue| F[SetSwitchValue Method]
+ C -->|RescanDevices| G[RescanDevices Method]
+ C -->|Other| H[Other Methods]
+
+ D --> I[Update Switch Info]
+ E --> J[Clear Switch Info]
+ F --> K[Update Switch Value]
+ G --> L[Update Device List]
+ I --> M[Broadcast Switch Info]
+ J --> M
+ K --> M
+ L --> M
+ M --> N[Notify Status]
+ H --> N
+ N --> O[Update UI]
+```
+
+### Step-by-Step Flowcharts
+
+#### 1. Connect Method
+
+The `Connect` method establishes a connection to the selected switch device.
+
+```mermaid
+flowchart TD
+ A[Start] --> B[Acquire Semaphore]
+ B --> C[Disconnect Existing Connection]
+ C --> D{Check Device ID}
+ D -->|No_Device| E[Set Device ID]
+ D -->|Valid| F[Update Status to Connecting]
+ F --> G[Initialize Cancellation Token]
+ G --> H[Connect to Device]
+ H --> I{Check Connection}
+ I -->|Connected| J[Update Switch Hub]
+ I -->|Not Connected| K[Notify Error]
+ J --> L[Initialize Switch Collections]
+ L --> M[Update Switch Info]
+ M --> N[Start Update Timer]
+ N --> O[Notify Success]
+ O --> P[Release Semaphore]
+ P --> Q[End]
+ K --> P
+```
+
+#### 2. Disconnect Method
+
+The `Disconnect` method terminates the connection and cleans up resources.
+
+```mermaid
+flowchart TD
+ A[Start] --> B{Check if Connected}
+ B -->|Yes| C[Stop Update Timer]
+ B -->|No| D[Skip Stop Timer]
+ C --> E[Disconnect Device]
+ E --> F[Clear Switch Collections]
+ F --> G[Reset Switch Info]
+ G --> H[Notify Disconnection]
+ H --> I[Release Semaphore]
+ I --> J[End]
+ D --> I
+```
+
+#### 3. SetSwitchValue Method
+
+The `SetSwitchValue` method sets the value of a writable switch and verifies the update.
+
+```mermaid
+flowchart TD
+ A[Start] --> B[Set Switch Value]
+ B --> C[Poll Switch]
+ C --> D{Check Value Difference}
+ D -->|Within Tolerance| E[Success]
+ D -->|Not Within Tolerance| F[Wait and Retry]
+ F --> G{Check Timeout}
+ G -->|Timeout| H[Notify Error]
+ G -->|No Timeout| C
+ E --> I[Update UI]
+ H --> I
+ I --> J[End]
+```
+
+#### 4. RescanDevices Method
+
+The `RescanDevices` method refreshes the list of available devices.
+
+```mermaid
+flowchart TD
+ A[Start] --> B[Get Equipment from Device Chooser]
+ B --> C[Update Device List]
+ C --> D[Return Device IDs]
+ D --> E[Update UI]
+ E --> F[End]
+```
diff --git a/doc/loading.drawio b/doc/loading.drawio
new file mode 100644
index 00000000..5bc0f8c9
--- /dev/null
+++ b/doc/loading.drawio
@@ -0,0 +1,698 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/task/autofocus/autofocus.md b/doc/task/autofocus/autofocus.md
new file mode 100644
index 00000000..3fd8fc73
--- /dev/null
+++ b/doc/task/autofocus/autofocus.md
@@ -0,0 +1,114 @@
+# RunAutofocus
+
+The `RunAutofocus` class is part of the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application. It manages the autofocus process for imaging sequences, ensuring the best focus is achieved for astronomical observations.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Autofocus`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Profile.Interfaces`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Utility.WindowService`
+ - `NINA.Core.Model.Equipment`
+ - `NINA.Core.Locale`
+ - `NINA.WPF.Base.Interfaces.ViewModel`
+ - `NINA.WPF.Base.Interfaces`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Autofocus_RunAutofocus_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Autofocus_RunAutofocus_Description")]
+[ExportMetadata("Icon", "AutoFocusSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Focuser")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class RunAutofocus : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **profileService**: Interface for accessing profile settings.
+- **history**: Interface for managing image history.
+- **cameraMediator**: Interface for interacting with the camera.
+- **filterWheelMediator**: Interface for interacting with the filter wheel.
+- **focuserMediator**: Interface for interacting with the focuser.
+- **autoFocusVMFactory**: Factory for creating autofocus view models.
+- **WindowServiceFactory**: Factory for creating window services.
+
+### Constructor
+
+The constructor initializes the `RunAutofocus` class with various services and mediators necessary for the autofocus process.
+
+```csharp
+[ImportingConstructor]
+public RunAutofocus(
+ IProfileService profileService, IImageHistoryVM history, ICameraMediator cameraMediator, IFilterWheelMediator filterWheelMediator, IFocuserMediator focuserMediator, IAutoFocusVMFactory autoFocusVMFactory)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `RunAutofocus` instance.
+- **Execute(IProgress progress, CancellationToken token)**: Starts the autofocus process and handles the UI and autofocus execution.
+- **Validate()**: Checks if the camera and focuser are connected and ready for autofocus.
+- **GetEstimatedDuration()**: Estimates the duration of the autofocus process based on settings and hardware.
+- **ToString()**: Provides a string representation of the `RunAutofocus` instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `RunAutofocus` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Create Autofocus ViewModel]
+ B --> C[Show Autofocus Window]
+ C --> D[Get Selected Filter]
+ D --> E[Start Autofocus]
+ E --> F{Autofocus Successful?}
+ F -- No --> G[Handle Failure]
+ F -- Yes --> H[Append Autofocus Point]
+ H --> I[Close Autofocus Window]
+ G --> I
+```
+
+### Flowchart Explanation
+
+1. **Create Autofocus ViewModel**: Creates a new autofocus view model using `autoFocusVMFactory`.
+2. **Show Autofocus Window**: Displays the autofocus UI window.
+3. **Get Selected Filter**: Retrieves the selected filter from the filter wheel if available.
+4. **Start Autofocus**: Initiates the autofocus process and obtains a report.
+5. **Autofocus Successful?**: Checks if the autofocus was successful. If not, handles the failure.
+6. **Append Autofocus Point**: Adds the result of the autofocus to the image history.
+7. **Close Autofocus Window**: Closes the autofocus UI window after a delay.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of `RunAutofocus` with the same configuration as the current instance.
+
+#### `Execute`
+
+1. **Create Autofocus ViewModel**: Initializes and displays the autofocus UI.
+2. **Start Autofocus**: Executes the autofocus process and captures the result.
+3. **Handle Failure**: Manages any errors during the autofocus process.
+4. **Append Autofocus Point**: Updates the image history with the new autofocus point.
+5. **Close Autofocus Window**: Closes the UI window after a delay.
+
+#### `Validate`
+
+1. **Camera Check**: Verifies that the camera is connected.
+2. **Focuser Check**: Verifies that the focuser is connected.
+3. **Update Issues**: Updates the list of issues based on connectivity checks.
+
+#### `GetEstimatedDuration`
+
+Calculates the estimated duration of the autofocus process based on settings and hardware characteristics. Considers exposure times, focuser settings, and number of attempts.
+
+#### `ToString`
+
+Provides a string representation of the `RunAutofocus` instance, including the category and item name.
diff --git a/doc/task/camera/smart_epxosure.md b/doc/task/camera/smart_epxosure.md
new file mode 100644
index 00000000..e974dfc8
--- /dev/null
+++ b/doc/task/camera/smart_epxosure.md
@@ -0,0 +1,71 @@
+# SmartExposure Class Overview
+
+The `SmartExposure` class is a key component within the N.I.N.A. (Nighttime Imaging 'N' Astronomy) software, designed to handle imaging sequences. Below is a detailed breakdown of its logic, event handling, validation, cloning, and more.
+
+## Key Functionalities
+
+- **Deserialization Initialization**
+
+ - Clears all sequence items, conditions, and triggers during the deserialization process to ensure a clean start.
+
+- **Constructor**
+
+ - Accepts dependencies like `profileService`, `cameraMediator`, and `filterWheelMediator`.
+ - Initializes core components including `SwitchFilter`, `TakeExposure`, `LoopCondition`, and `DitherAfterExposures`.
+
+- **Event Handling**
+
+ - Monitors changes to the `SwitchFilter` property. If the filter changes during sequence creation or execution, the progress is reset.
+
+- **Error Handling**
+
+ - Incorporates properties for managing error behavior (`ErrorBehavior`) and retry attempts (`Attempts`), ensuring robust error management during execution.
+
+- **Validation**
+
+ - The `Validate` method checks the configuration of all internal components and returns a boolean indicating whether the sequence is valid for execution.
+
+- **Cloning**
+
+ - Provides a `Clone` method to create a deep copy of the `SmartExposure` instance, including all its associated components.
+
+- **Duration Estimation**
+
+ - Calculates the estimated duration for the sequence based on the exposure settings.
+
+- **Interrupt Handling**
+ - If an interruption occurs, it is rerouted to the parent sequence for consistent behavior.
+
+## Flowchart
+
+```mermaid
+graph TD;
+ A[Start] --> B{OnDeserializing};
+ B --> C(Clear Items);
+ B --> D(Clear Conditions);
+ B --> E(Clear Triggers);
+ C --> F[Constructor Called];
+ D --> F;
+ E --> F;
+ F --> G[Initialize SwitchFilter];
+ F --> H[Initialize TakeExposure];
+ F --> I[Initialize LoopCondition];
+ F --> J[Initialize DitherAfterExposures];
+ G --> K[Event Handling];
+ H --> K;
+ I --> K;
+ J --> K;
+ K --> L{Property Changed?};
+ L --> M[Reset Progress];
+ L --> N[Do Nothing];
+ M --> O[Validate];
+ N --> O;
+ O --> P{Valid Sequence?};
+ P --> Q[Return True];
+ P --> R[Return False];
+ Q --> S[Cloning];
+ R --> S;
+ S --> T[Estimate Duration];
+ T --> U[Interrupt Handling];
+ U --> V[End];
+```
diff --git a/doc/task/camera/take_many_exposure.md b/doc/task/camera/take_many_exposure.md
new file mode 100644
index 00000000..e923cdce
--- /dev/null
+++ b/doc/task/camera/take_many_exposure.md
@@ -0,0 +1,77 @@
+# TakeManyExposures Class Detailed Overview
+
+The `TakeManyExposures` class is part of the Nighttime Imaging 'N' Astronomy (N.I.N.A.) software, designed to manage multiple exposures in a sequence. This class builds upon the `SequentialContainer` class and integrates components like `TakeExposure` and `LoopCondition` to facilitate repeated image capturing operations. Below is a detailed breakdown of its functionalities, logic, and methods.
+
+## Key Functionalities
+
+1. **Initialization and Cloning**:
+ - The constructor initializes key components such as `TakeExposure` and `LoopCondition`.
+ - The `Clone` method creates a deep copy of the `TakeManyExposures` instance, ensuring that all settings and configurations are preserved.
+
+2. **Deserialization Handling (`OnDeserializing` Method)**:
+ - Clears the `Items`, `Conditions`, and `Triggers` collections to ensure a clean state when the object is deserialized.
+
+3. **Error Handling and Attempt Management**:
+ - The `ErrorBehavior` property controls how errors are handled during execution. It propagates the error behavior setting to all child items.
+ - The `Attempts` property determines the number of retry attempts for each operation and is also propagated to all child items.
+
+4. **Validation (`Validate` Method)**:
+ - Validates the internal `TakeExposure` component to ensure that all necessary settings are correct.
+ - If validation fails, the issues are collected and made available for further inspection.
+
+5. **Execution Flow**:
+ - The main execution logic is driven by the `TakeExposure` component and the `LoopCondition`, which controls the repetition of the exposure sequence.
+ - If an interruption occurs, the class routes the interrupt request to the parent sequence, ensuring consistent behavior.
+
+6. **Duration Estimation (`GetEstimatedDuration` Method)**:
+ - Calculates the estimated total duration of the exposure sequence based on the settings of the `TakeExposure` component.
+
+## Flowchart
+
+```mermaid
+graph TD;
+ A[Start] --> B{OnDeserializing?};
+ B --> |Yes| C[Clear Items];
+ B --> |No| D[Initialize Components];
+ C --> D;
+ D --> E[Set ErrorBehavior];
+ E --> F[Set Attempts];
+ F --> G[Validate];
+ G --> H{Validation Successful?};
+ H --> |Yes| I[Execute Loop Condition];
+ H --> |No| J[Return Issues];
+ I --> K[Take Exposure];
+ K --> L{Interrupt?};
+ L --> |Yes| M[Interrupt Parent];
+ L --> |No| N[Repeat Based on Loop Condition];
+ N --> O[End];
+ M --> O;
+ J --> O;
+```
+
+## Detailed Methods and Properties
+
+1. **Constructor**:
+ - Initializes the `TakeExposure` component, which handles individual exposures, and the `LoopCondition`, which manages the repetition of exposures.
+
+2. **Clone Method**:
+ - Creates a copy of the `TakeManyExposures` object, duplicating all its settings and configurations for reuse.
+
+3. **OnDeserializing Method**:
+ - Ensures that the collections `Items`, `Conditions`, and `Triggers` are cleared during deserialization to avoid conflicts and ensure a fresh start.
+
+4. **ErrorBehavior Property**:
+ - Propagates the error behavior setting to all child items, ensuring that error handling is consistent across the entire sequence.
+
+5. **Attempts Property**:
+ - Propagates the retry attempts setting to all child items, ensuring that each operation has the same number of retry attempts.
+
+6. **Validate Method**:
+ - Validates the settings of the `TakeExposure` component, checking for any issues that might prevent the sequence from executing correctly.
+ - Returns `true` if validation is successful, otherwise collects and returns issues.
+
+7. **Interrupt Method**:
+ - Handles interrupt requests by forwarding them to the parent sequence, ensuring that any ongoing sequence can be halted appropriately.
+
+8. **GetEstimatedDuration Method**:
+ - Calculates the total estimated duration of the sequence based on the exposure settings and the number of repetitions defined by the `LoopCondition`.
diff --git a/doc/task/camera/take_subframe_exposure.md b/doc/task/camera/take_subframe_exposure.md
new file mode 100644
index 00000000..b9daf32c
--- /dev/null
+++ b/doc/task/camera/take_subframe_exposure.md
@@ -0,0 +1,155 @@
+# `TakeSubframeExposure` Class Overview
+
+The `TakeSubframeExposure` class is part of the **N.I.N.A.** project and extends the `SequenceItem` class to manage subframe exposures in astrophotography sequences.
+
+## Key Responsibilities
+
+- Handles the capture of subframe exposures using a connected camera.
+- Manages camera settings such as exposure time, gain, offset, and region of interest (ROI).
+- Validates the camera configuration and the file paths for saving captured images.
+- Supports cloning of its instances to create identical exposure sequences.
+- Integrates with other components such as `CameraMediator`, `ImagingMediator`, and `ImageSaveMediator` for coordinated operation.
+
+## Constructor
+
+### Importing Constructor
+
+```csharp
+[ImportingConstructor]
+public TakeSubframeExposure(
+ IProfileService profileService,
+ ICameraMediator cameraMediator,
+ IImagingMediator imagingMediator,
+ IImageSaveMediator imageSaveMediator,
+ IImageHistoryVM imageHistoryVM)
+```
+
+- **Parameters:**
+ - `profileService`: Provides access to the current profile settings.
+ - `cameraMediator`: Facilitates interaction with the camera.
+ - `imagingMediator`: Manages imaging processes like capturing and preparing images.
+ - `imageSaveMediator`: Handles the saving of images.
+ - `imageHistoryVM`: Maintains the history of captured images.
+
+### Cloning Constructor
+
+```csharp
+private TakeSubframeExposure(TakeSubframeExposure cloneMe)
+```
+
+- Creates a clone of an existing `TakeSubframeExposure` object.
+
+## Methods
+
+### `Execute`
+
+```csharp
+public override async Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Purpose:** Executes the subframe exposure sequence.
+- **Flow:**
+ 1. Retrieves target information if available.
+ 2. Determines the ROI for subframe capture if the camera supports subsampling.
+ 3. Initiates the capture sequence and processes the image.
+ 4. Increments the exposure count after a successful capture.
+
+**Flowchart:**
+
+```mermaid
+graph TD
+ A[Start Execute] --> B[Retrieve Target]
+ B --> C{Can SubSample?}
+ C -->|Yes| D[Calculate ROI]
+ C -->|No| E[Log Warning]
+ D --> F[Initiate Capture Sequence]
+ E --> F
+ F --> G[Process Image Data]
+ G --> H{Is Light Sequence?}
+ H -->|Yes| I[Add to Image History]
+ H -->|No| J[Complete Execution]
+ I --> J
+ J --> K[Increment Exposure Count]
+ K --> L[End]
+```
+
+### `Validate`
+
+```csharp
+public bool Validate()
+```
+
+- **Purpose:** Validates the camera configuration and file paths before execution.
+- **Flow:**
+ 1. Checks camera connection status.
+ 2. Validates gain and offset values.
+ 3. Checks if the file path for saving images is valid.
+ 4. Returns a boolean indicating if the configuration is valid.
+
+**Flowchart:**
+
+```mermaid
+graph TD
+ A[Start Validation] --> B{Camera Connected?}
+ B -->|No| C[Add Issue: Camera Not Connected]
+ B -->|Yes| D[Validate Gain and Offset]
+ D --> E{File Path Valid?}
+ E -->|No| F[Add Issue: Invalid File Path]
+ E -->|Yes| G[Validation Successful]
+ F --> G
+ G --> H[Return Validation Result]
+```
+
+### `ProcessImageData`
+
+```csharp
+private async Task ProcessImageData(IDeepSkyObjectContainer dsoContainer, IExposureData exposureData, IProgress progress, CancellationToken token)
+```
+
+- **Purpose:** Processes the captured image data and saves it to the specified location.
+- **Flow:**
+ 1. Prepares the image for saving based on the sequence type.
+ 2. Retrieves image statistics if it’s a light sequence.
+ 3. Adds target metadata if available.
+ 4. Saves the image through `imageSaveMediator`.
+
+**Flowchart:**
+
+```mermaid
+graph TD
+ A[Start Process Image Data] --> B[Prepare Image]
+ B --> C{Is Light Sequence?}
+ C -->|Yes| D[Retrieve Image Statistics]
+ C -->|No| E[Skip Statistics]
+ D --> F[Add Target Metadata]
+ E --> F
+ F --> G[Save Image]
+ G --> H[End]
+```
+
+### `Clone`
+
+```csharp
+public override object Clone()
+```
+
+- **Purpose:** Creates and returns a deep copy of the `TakeSubframeExposure` object.
+
+### `ToString`
+
+```csharp
+public override string ToString()
+```
+
+- **Purpose:** Provides a string representation of the current state of the `TakeSubframeExposure` object.
+
+## Properties
+
+- **ROI (Region of Interest):** Defines the fraction of the sensor to be used for capturing.
+- **ExposureTime:** The duration of each exposure.
+- **Gain:** The gain setting of the camera.
+- **Offset:** The offset setting of the camera.
+- **Binning:** The binning mode used for capturing images.
+- **ImageType:** The type of image being captured (e.g., LIGHT, DARK).
+- **ExposureCount:** The number of exposures captured so far.
+- **CameraInfo:** Holds information about the camera’s capabilities and settings.
diff --git a/doc/task/camera/task_exposure.md b/doc/task/camera/task_exposure.md
new file mode 100644
index 00000000..76bd0c1f
--- /dev/null
+++ b/doc/task/camera/task_exposure.md
@@ -0,0 +1,82 @@
+# TakeExposure Class Detailed Overview
+
+The `TakeExposure` class is part of the Nighttime Imaging 'N' Astronomy (N.I.N.A.) software, specifically designed for managing the exposure process during an imaging sequence. Below is a detailed breakdown of its functionalities, logic, validation, and more.
+
+## Key Functionalities
+
+1. **Initialization and Cloning**:
+
+ - The constructor initializes key components such as mediators (`cameraMediator`, `imagingMediator`, etc.) and sets default values for properties like `Gain`, `Offset`, and `ImageType`.
+ - The `Clone` method creates a deep copy of the `TakeExposure` instance, ensuring all settings are duplicated accurately.
+
+2. **Validation (`Validate` Method)**:
+
+ - Ensures the camera is connected and the gain and offset values are within acceptable ranges.
+ - Checks that the image file path is set and valid.
+
+3. **Execution (`Execute` Method)**:
+
+ - Handles the process of taking an exposure, including capturing the image, processing the data, and saving it.
+ - Integrates with the `imagingMediator` to perform the actual capture and image processing tasks.
+ - Updates the exposure count after each successful capture.
+
+4. **Image Processing (`ProcessImageData` Method)**:
+
+ - Processes the captured image data, including preparing the image and updating metadata.
+ - If the sequence is for light frames, it populates statistics and associates the image with the current target.
+
+5. **Duration Estimation (`GetEstimatedDuration` Method)**:
+
+ - Returns the estimated duration for the exposure based on the `ExposureTime` property.
+
+6. **Parent Validation (`AfterParentChanged` Method)**:
+ - Re-validates the sequence item when its parent is changed to ensure consistency.
+
+## Flowchart
+
+```mermaid
+graph TD;
+ A[Start] --> B{Validate?};
+ B --> |Valid| C[Initialize Components];
+ B --> |Invalid| D[Return Issues];
+ C --> E[Execute];
+ E --> F[Capture Image];
+ F --> G[Process Image Data];
+ G --> H{Is Light Sequence?};
+ H --> |Yes| I[Add to Image History];
+ H --> |No| J[Skip Image History];
+ I --> K[Save Image];
+ J --> K;
+ K --> L[Increment Exposure Count];
+ L --> M[End];
+```
+
+## Detailed Methods and Properties
+
+1. **Constructor**:
+
+ - Initializes properties such as `Gain`, `Offset`, `ImageType`, and sets up the necessary mediators for camera and image handling.
+
+2. **Clone Method**:
+
+ - Creates a copy of the current `TakeExposure` object with all its properties, ensuring that the exposure settings are carried over.
+
+3. **Execute Method**:
+
+ - Manages the main sequence of actions for taking an exposure.
+ - Integrates with the `imagingMediator` to capture the image.
+ - Handles special logic for deep sky object containers, adjusting the exposure count if necessary.
+
+4. **ProcessImageData Method**:
+
+ - Prepares and processes the captured image data.
+ - Updates metadata, such as target name and coordinates, before saving the image.
+ - Handles additional tasks like calculating statistics if the sequence involves light frames.
+
+5. **Validation Method**:
+
+ - Checks the camera's connection status and verifies that gain and offset values are within the acceptable range.
+ - Ensures the file path for saving images is valid.
+
+6. **GetEstimatedDuration Method**:
+ - Returns the estimated duration of the exposure based on the set `ExposureTime`.
diff --git a/doc/task/filterwheel/switch.md b/doc/task/filterwheel/switch.md
new file mode 100644
index 00000000..74df5b08
--- /dev/null
+++ b/doc/task/filterwheel/switch.md
@@ -0,0 +1,111 @@
+# SwitchFilter
+
+The `SwitchFilter` class manages the process of switching filters in a filter wheel. It interfaces with both profile services and filter wheel hardware to ensure that the correct filter is selected and applied.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.FilterWheel`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Profile.Interfaces`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+ - `NINA.Core.Utility`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_FilterWheel_SwitchFilter_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_FilterWheel_SwitchFilter_Description")]
+[ExportMetadata("Icon", "FW_NoFill_SVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_FilterWheel")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SwitchFilter : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **profileService**: Provides access to profile services, including filter settings.
+- **filterWheelMediator**: Handles communication with the filter wheel hardware.
+- **issues**: A list to capture validation issues.
+- **Filter**: The filter to be selected or applied.
+
+### Constructor
+
+The constructor initializes the `SwitchFilter` class with a `profileService` and `filterWheelMediator`. It also sets up an event handler to respond to profile changes.
+
+```csharp
+[ImportingConstructor]
+public SwitchFilter(IProfileService profileservice, IFilterWheelMediator filterWheelMediator)
+```
+
+### Key Methods
+
+- **OnDeserialized(StreamingContext context)**: Ensures the filter is correctly matched after deserialization.
+- **MatchFilter()**: Attempts to match the selected filter with the current profile's filter settings.
+- **ProfileService_ProfileChanged(object sender, EventArgs e)**: Updates the filter when the profile changes.
+- **Execute(IProgress progress, CancellationToken token)**: Switches to the specified filter.
+- **Validate()**: Checks if the filter wheel is connected and valid.
+- **AfterParentChanged()**: Revalidates the state after the parent changes.
+- **ToString()**: Returns a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `SwitchFilter` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Filter Selected?}
+ B -->|No| C[Throw Exception: No Filter Selected]
+ B -->|Yes| D{Is Filter Wheel Connected?}
+ D -->|No| E[Add Error: Filter Wheel Not Connected]
+ D -->|Yes| F[Change Filter Using Mediator]
+ F --> G[Await Filter Change Completion]
+ G --> H[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Filter Selected?**: Checks if a filter has been selected. If not, an exception is thrown.
+ - **No:** Throws an exception indicating that no filter was selected.
+ - **Yes:** Proceeds to check if the filter wheel is connected.
+2. **Is Filter Wheel Connected?**: Checks if the filter wheel is connected.
+ - **No:** Adds an error indicating that the filter wheel is not connected.
+ - **Yes:** Commands the filter wheel to change to the selected filter.
+3. **Change Filter Using Mediator**: Uses the filter wheel mediator to change the filter.
+4. **Await Filter Change Completion**: Waits for the filter change to complete.
+5. **End Execution**: Marks the end of the execution process.
+
+### Detailed Method Descriptions
+
+#### `OnDeserialized`
+
+This method ensures that the filter is correctly matched after deserialization by calling `MatchFilter`.
+
+#### `MatchFilter`
+
+Attempts to match the selected filter with the filter settings from the active profile. If the filter can't be found by name, it tries to match by position.
+
+#### `ProfileService_ProfileChanged`
+
+Updates the filter settings when the profile changes, ensuring that the `Filter` property is in sync with the active profile.
+
+#### `Execute`
+
+Switches to the specified filter. If no filter is selected or if the filter wheel is not connected, it handles these scenarios appropriately.
+
+#### `Validate`
+
+Checks if the filter wheel is connected and if the selected filter is valid. Updates the `Issues` property with any validation errors.
+
+#### `AfterParentChanged`
+
+Revalidates the state when the parent of this sequence item changes to ensure the filter settings are still valid.
+
+#### `ToString`
+
+Provides a string representation of the `SwitchFilter` instance, including the category, item name, and selected filter.
diff --git a/doc/task/focuser/move_absolute.md b/doc/task/focuser/move_absolute.md
new file mode 100644
index 00000000..447653cc
--- /dev/null
+++ b/doc/task/focuser/move_absolute.md
@@ -0,0 +1,88 @@
+# MoveFocuserAbsolute
+
+The `MoveFocuserAbsolute` class in the N.I.N.A. application is responsible for controlling the focuser's movement to a specified absolute position during an astronomical imaging session. The focuser plays a crucial role in ensuring the telescope's optics are precisely aligned for capturing sharp images. This class ensures that the focuser moves to the exact position specified and validates that the focuser system is connected before attempting to move it.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Focuser`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Focuser_MoveFocuserAbsolute_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Focuser_MoveFocuserAbsolute_Description")]
+[ExportMetadata("Icon", "MoveFocuserSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Focuser")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class MoveFocuserAbsolute : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **focuserMediator**: An interface that handles communication with the focuser hardware, specifically managing the movement to an absolute position.
+- **Position**: The absolute position to which the focuser should move.
+- **Issues**: A list of issues identified during the validation of the focuser's connection status.
+
+### Constructor
+
+The constructor initializes the `MoveFocuserAbsolute` class by setting up the connection with the focuser mediator, ensuring that the class can interact with the focuser system to move it to the specified position.
+
+```csharp
+[ImportingConstructor]
+public MoveFocuserAbsolute(IFocuserMediator focuserMediator)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: Moves the focuser to the specified absolute position using the `focuserMediator`.
+- **Validate()**: Ensures that the focuser system is connected before attempting to move the focuser. Updates the `Issues` list if any problems are found.
+- **AfterParentChanged()**: Re-validates the focuser connection whenever the parent sequence item changes.
+- **Clone()**: Creates a new instance of the `MoveFocuserAbsolute` object, preserving its properties and metadata.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `MoveFocuserAbsolute` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Focuser Connected?}
+ B -->|No| C[Throw Exception: Focuser Not Connected]
+ B -->|Yes| D[Move Focuser to Position: Position]
+ D --> E[Await Movement Completion]
+ E --> F[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Focuser Connected?**: The process begins by verifying that the focuser is connected and ready.
+ - **No:** If the focuser is not connected, an exception is thrown, aborting the process.
+ - **Yes:** If connected, the process continues to move the focuser to the specified position.
+2. **Move Focuser to Position**: The focuser is instructed to move to the absolute position specified by the `Position` property.
+3. **Await Movement Completion**: The system waits for the focuser to reach the desired position.
+4. **End Execution**: The method completes execution after successfully moving the focuser.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method is the primary function of the `MoveFocuserAbsolute` class. It uses the `focuserMediator` to interact with the focuser hardware, sending the command to move the focuser to a specified absolute position. The method ensures that the focuser reaches the correct position, and if any issues arise, it handles them appropriately.
+
+#### `Validate` Method
+
+The `Validate` method checks that the focuser system is properly connected before allowing the movement to occur. It updates the `Issues` list with any problems that it encounters, such as the focuser being disconnected. This validation is crucial to prevent errors during execution.
+
+#### `AfterParentChanged` Method
+
+The `AfterParentChanged` method is called whenever the parent sequence item changes. This triggers a re-validation of the `MoveFocuserAbsolute` class to ensure that any contextual changes—such as different equipment or settings—are accounted for. This helps maintain the reliability of the sequence by confirming that moving the focuser is still appropriate in the new context.
+
+#### `Clone` Method
+
+The `Clone` method creates a new instance of the `MoveFocuserAbsolute` class, preserving all properties and metadata from the original instance. This is useful for repeating the focuser movement in different parts of a sequence without manually configuring each instance.
diff --git a/doc/task/focuser/move_by_temperature.md b/doc/task/focuser/move_by_temperature.md
new file mode 100644
index 00000000..bcae2fc9
--- /dev/null
+++ b/doc/task/focuser/move_by_temperature.md
@@ -0,0 +1,110 @@
+# MoveFocuserByTemperature
+
+The `MoveFocuserByTemperature` class in the N.I.N.A. application is designed to adjust the focuser position based on temperature changes. This is particularly useful in astrophotography, where temperature fluctuations can cause the telescope's focus to drift, affecting image sharpness. This class ensures that the focuser compensates for temperature changes, either by moving to an absolute position or by adjusting the position relative to the last known temperature.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Focuser`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+ - `NINA.Core.Utility`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Focuser_MoveFocuserByTemperature_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Focuser_MoveFocuserByTemperature_Description")]
+[ExportMetadata("Icon", "MoveFocuserByTemperatureSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Focuser")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class MoveFocuserByTemperature : SequenceItem, IValidatable, IFocuserConsumer
+```
+
+### Class Properties
+
+- **focuserMediator**: Interface that handles communication with the focuser hardware.
+- **Slope**: The slope used to calculate the focuser position based on temperature.
+- **Intercept**: The intercept used in the linear equation to determine the absolute focuser position.
+- **Absolute**: Boolean value indicating whether the focuser should move to an absolute position (`true`) or adjust position relative to temperature changes (`false`).
+- **Issues**: List of validation issues, such as connectivity problems or missing temperature data.
+- **MiniDescription**: A brief description of the focusing logic used, displayed to the user.
+
+### Static Fields
+
+- **lastTemperature**: Stores the last known temperature from the autofocus or manual focus operations.
+- **lastRoundoff**: Stores the last roundoff value used for precise adjustments.
+
+### Constructor
+
+The constructor initializes the `MoveFocuserByTemperature` class by associating it with a `focuserMediator`, ensuring it can interact with the focuser system to adjust the position based on temperature.
+
+```csharp
+[ImportingConstructor]
+public MoveFocuserByTemperature(IFocuserMediator focuserMediator)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: Adjusts the focuser position based on the current temperature and the provided slope and intercept.
+- **Validate()**: Ensures that the focuser system is connected and that temperature data is available.
+- **AfterParentChanged()**: Re-validates the focuser connection whenever the parent sequence item changes.
+- **Clone()**: Creates a new instance of the `MoveFocuserByTemperature` object, preserving its properties and metadata.
+- **UpdateDeviceInfo(Equipment.Equipment.MyFocuser.FocuserInfo deviceInfo)**: Updates the device information.
+- **UpdateEndAutoFocusRun(AutoFocusInfo info)**: Logs the temperature after an autofocus run.
+- **UpdateUserFocused(Equipment.Equipment.MyFocuser.FocuserInfo info)**: Logs the temperature after a user focuses the telescope.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `MoveFocuserByTemperature` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Focuser Connected?}
+ B -->|No| C[Throw Exception: Focuser Not Connected]
+ B -->|Yes| D{Is Temperature Data Available?}
+ D -->|No| E[Log Warning: No Temperature Data]
+ D -->|Yes| F{Absolute Mode?}
+ F -->|Yes| G[Calculate Absolute Position: Slope * Temperature + Intercept]
+ G --> H[Move Focuser to Calculated Position]
+ F -->|No| I[Calculate Relative Position Based on Slope]
+ I --> J[Move Focuser by Relative Position]
+ H & J --> K[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Focuser Connected?**: The process begins by checking if the focuser is connected.
+ - **No:** If not connected, an exception is thrown, and the process stops.
+ - **Yes:** If connected, the process continues to check temperature data.
+2. **Is Temperature Data Available?**: Ensures that valid temperature data is available.
+ - **No:** Logs a warning and stops further execution.
+ - **Yes:** Proceeds to adjust the focuser based on temperature.
+3. **Absolute Mode?**: Checks if the adjustment is in absolute mode or relative mode.
+ - **Yes (Absolute Mode):** Calculates the absolute position using the formula `Slope * Temperature + Intercept`.
+ - **No (Relative Mode):** Calculates the position adjustment relative to temperature changes.
+4. **Move Focuser**: Executes the calculated focuser movement, either to an absolute position or a relative adjustment.
+5. **End Execution**: Completes the execution process.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method is the core function of the `MoveFocuserByTemperature` class. It adjusts the focuser's position based on the current temperature reading from the focuser hardware. Depending on whether the `Absolute` property is set to `true` or `false`, the method either calculates an absolute position using the provided slope and intercept or adjusts the position relative to the temperature change.
+
+#### `Validate` Method
+
+The `Validate` method checks the connectivity of the focuser system and ensures that temperature data is available. If the focuser is not connected or temperature data is missing, the method updates the `Issues` list with the relevant validation errors, preventing execution until the issues are resolved.
+
+#### `Clone` Method
+
+The `Clone` method creates a new instance of the `MoveFocuserByTemperature` class, preserving all the properties and metadata. This is useful for creating multiple instances of the same focuser adjustment logic within a sequence, ensuring consistency across different steps.
+
+#### `UpdateEndAutoFocusRun` and `UpdateUserFocused` Methods
+
+These methods log the temperature after an autofocus run or user focus operation. This data is stored in `lastTemperature` and can be used for further adjustments or logging purposes, ensuring that the focuser remains in optimal alignment throughout the imaging session.
diff --git a/doc/task/focuser/move_relative.md b/doc/task/focuser/move_relative.md
new file mode 100644
index 00000000..5fac6d43
--- /dev/null
+++ b/doc/task/focuser/move_relative.md
@@ -0,0 +1,88 @@
+# MoveFocuserRelative
+
+The `MoveFocuserRelative` class is part of the N.I.N.A. application, and it manages the movement of the focuser relative to its current position. This functionality is useful for fine-tuning the focus without needing to specify an absolute position.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Focuser`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Focuser_MoveFocuserRelative_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Focuser_MoveFocuserRelative_Description")]
+[ExportMetadata("Icon", "MoveFocuserRelativeSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Focuser")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class MoveFocuserRelative : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **focuserMediator**: Manages communication with the focuser hardware.
+- **RelativePosition**: The amount by which to move the focuser relative to its current position.
+- **issues**: A list to capture validation issues.
+
+### Constructor
+
+The constructor initializes the `MoveFocuserRelative` class with a `focuserMediator`, allowing interaction with the focuser system.
+
+```csharp
+[ImportingConstructor]
+public MoveFocuserRelative(IFocuserMediator focuserMediator)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: Moves the focuser by a relative amount specified by the `RelativePosition` property.
+- **Validate()**: Ensures that the focuser system is connected.
+- **AfterParentChanged()**: Validates the state after the parent changes.
+- **ToString()**: Returns a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `MoveFocuserRelative` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Focuser Connected?}
+ B -->|No| C[Throw Exception: Focuser Not Connected]
+ B -->|Yes| D[Move Focuser by Relative Position]
+ D --> E[Await Movement Completion]
+ E --> F[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Focuser Connected?**: Checks if the focuser is connected. If not, an exception is thrown.
+ - **No:** Throws an exception indicating that the focuser is not connected.
+ - **Yes:** Proceeds to move the focuser.
+2. **Move Focuser by Relative Position**: Commands the focuser to move by the amount specified in `RelativePosition`.
+3. **Await Movement Completion**: Waits for the focuser to complete its movement.
+4. **End Execution**: Marks the end of the execution process.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method instructs the focuser to move by the amount specified in `RelativePosition`. This relative movement adjusts the focus based on the current position rather than an absolute position.
+
+#### `Validate` Method
+
+The `Validate` method checks if the focuser is connected. If not, it adds an appropriate validation error to the `Issues` list.
+
+#### `AfterParentChanged` Method
+
+The `AfterParentChanged` method is used to revalidate the state when the parent of this sequence item changes.
+
+#### `ToString` Method
+
+The `ToString` method provides a string representation of the `MoveFocuserRelative` instance, including the category, item name, and the relative position.
diff --git a/doc/task/guider/dither.md b/doc/task/guider/dither.md
new file mode 100644
index 00000000..278a14be
--- /dev/null
+++ b/doc/task/guider/dither.md
@@ -0,0 +1,91 @@
+# Dither
+
+The `Dither` class in the N.I.N.A. application is designed to execute the dithering process during an astronomical imaging session. Dithering is a technique used to slightly move the telescope between exposures to reduce the impact of fixed pattern noise in the final stacked image. This class is essential for achieving higher-quality images by ensuring that noise patterns do not align across exposures.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Guider`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+ - `NINA.Profile.Interfaces`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Guider_Dither_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Guider_Dither_Description")]
+[ExportMetadata("Icon", "DitherSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Guider")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class Dither : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **guiderMediator**: Handles communication with the guider hardware to execute the dithering commands.
+- **profileService**: Provides access to the active profile settings, including guider configuration.
+- **Issues**: A list of issues found during the validation of the class, particularly related to the connection status of the guider.
+
+### Constructor
+
+The constructor initializes the `Dither` class with dependencies on the guider mediator and profile service, ensuring the necessary components are available for executing the dithering process.
+
+```csharp
+[ImportingConstructor]
+public Dither(IGuiderMediator guiderMediator, IProfileService profileService)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: This method executes the dithering process by issuing the dither command to the guider.
+- **Validate()**: Checks if the guider is connected and operational before attempting to dither.
+- **AfterParentChanged()**: Validates the connection status of the guider when the parent sequence item changes.
+- **GetEstimatedDuration()**: Returns an estimated duration for the dithering process, based on the profile's guider settings.
+- **Clone()**: Creates a deep copy of the `Dither` object.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `Dither` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Guider Connected?}
+ B -->|No| C[Add Issue: Guider Not Connected]
+ C --> D[Abort Execution]
+ B -->|Yes| E[Issue Dither Command to Guider]
+ E --> F[Await Dither Completion]
+ F --> G[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Guider Connected?:** The process begins by checking whether the guider is connected and ready to execute commands.
+ - **No:** If the guider is not connected, an issue is logged indicating the connection problem, and the execution is aborted.
+ - **Yes:** If the guider is connected, the process continues.
+2. **Issue Dither Command to Guider:** The `Dither` class sends a command to the guider to perform the dithering operation.
+3. **Await Dither Completion:** The system waits for the guider to complete the dithering process.
+4. **End Execution:** The dithering process concludes, and control is returned to the sequence executor.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method is responsible for issuing the dither command to the guider. It relies on the `guiderMediator` to communicate with the guider hardware. The method ensures that the guider is connected and ready before attempting to dither, thus preventing runtime errors.
+
+#### `Validate` Method
+
+The `Validate` method checks the connection status of the guider. If the guider is not connected, the method adds an issue to the `Issues` list, which can be reviewed by the user to troubleshoot the problem. This validation step is critical for ensuring that the dithering process can be executed without errors.
+
+#### `AfterParentChanged` Method
+
+The `AfterParentChanged` method is called whenever the parent sequence item is changed. It triggers a re-validation of the `Dither` item to ensure that any changes in the sequence context are taken into account, particularly in terms of equipment connectivity.
+
+#### `GetEstimatedDuration` Method
+
+The `GetEstimatedDuration` method returns the estimated time required to complete the dithering process. This estimate is based on the `SettleTimeout` value specified in the active profile's guider settings, providing a rough timeline for how long the dithering will take.
diff --git a/doc/task/guider/start_guiding.md b/doc/task/guider/start_guiding.md
new file mode 100644
index 00000000..e404da0a
--- /dev/null
+++ b/doc/task/guider/start_guiding.md
@@ -0,0 +1,103 @@
+# StartGuiding
+
+The `StartGuiding` class in the N.I.N.A. application is designed to initiate the guiding process during an astronomical imaging session. Guiding is a critical process in astrophotography, where a separate guider camera or system is used to keep the telescope precisely aligned with the target object. This class ensures that the guiding process starts correctly and optionally forces a new calibration.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Guider`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Guider_StartGuiding_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Guider_StartGuiding_Description")]
+[ExportMetadata("Icon", "GuiderSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Guider")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class StartGuiding : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **guiderMediator**: Manages communication with the guider hardware, handling the start of the guiding process.
+- **ForceCalibration**: A boolean flag indicating whether the guiding process should force a new calibration before starting.
+- **Issues**: A list of issues identified during validation, particularly related to the guider’s connection status and calibration capability.
+
+### Constructor
+
+The constructor initializes the `StartGuiding` class by setting up the connection with the guider mediator. This ensures that the class can interact with the guider system when executing the guiding process.
+
+```csharp
+[ImportingConstructor]
+public StartGuiding(IGuiderMediator guiderMediator)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: Starts the guiding process, optionally forcing a new calibration. If the process fails, an exception is thrown.
+- **Validate()**: Validates the connection to the guider and checks if forced calibration is possible, updating the `Issues` list if any problems are detected.
+- **AfterParentChanged()**: Re-validates the guider connection and capabilities whenever the parent sequence item changes.
+- **Clone()**: Creates a copy of the `StartGuiding` object, preserving its properties and metadata.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `StartGuiding` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Guider Connected?}
+ B -->|No| C[Throw Exception: Guider Not Connected]
+ B -->|Yes| D{Force Calibration?}
+ D -->|Yes| E{Can Guider Clear Calibration?}
+ E -->|No| F[Throw Exception: Cannot Clear Calibration]
+ E -->|Yes| G[Start Guiding with Calibration]
+ D -->|No| H[Start Guiding without Calibration]
+ G --> I[Await Guiding Completion]
+ H --> I[Await Guiding Completion]
+ I --> J{Guiding Started Successfully?}
+ J -->|No| K[Throw Exception: Failed to Start Guiding]
+ J -->|Yes| L[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Guider Connected?**: The process begins by verifying that the guider is connected and ready.
+ - **No:** If the guider is not connected, an exception is thrown, aborting the process.
+ - **Yes:** If connected, the process continues to the next step.
+2. **Force Calibration?**: Checks if the guiding process should force a new calibration.
+ - **Yes:** If calibration is required, the system checks if the guider can clear its current calibration.
+ - **No:** If no calibration is forced, guiding begins without recalibration.
+3. **Can Guider Clear Calibration?**: If calibration is forced, this step checks whether the guider can clear its existing calibration.
+ - **No:** If the guider cannot clear calibration, an exception is thrown.
+ - **Yes:** If it can, the system proceeds to start guiding with calibration.
+4. **Start Guiding**: The guiding process is initiated, either with or without calibration based on the previous steps.
+5. **Await Guiding Completion**: The system waits for the guiding process to either succeed or fail.
+6. **Guiding Started Successfully?**: A final check to confirm that guiding has started successfully.
+ - **No:** If guiding fails, an exception is thrown.
+ - **Yes:** If successful, the process completes.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method is the core of the `StartGuiding` class. It handles starting the guiding process, including the optional step of forcing a new calibration. The method uses the `guiderMediator` to interact with the guider hardware, ensuring the process is executed correctly. If any issues arise—such as a failure to start guiding or the inability to clear calibration—an exception is thrown to halt the sequence.
+
+#### `Validate` Method
+
+The `Validate` method checks the readiness of the guiding system. It ensures that the guider is connected and, if necessary, verifies that it can clear calibration data before starting a new calibration. The results of this validation are stored in the `Issues` list, which provides a way to identify and troubleshoot potential problems before executing the guiding process.
+
+#### `AfterParentChanged` Method
+
+The `AfterParentChanged` method is invoked whenever the parent sequence item changes. This triggers a re-validation of the `StartGuiding` class to ensure that any contextual changes—such as different equipment or settings—are taken into account. It helps maintain the integrity of the sequence by ensuring that guiding can be started successfully in the new context.
+
+#### `Clone` Method
+
+The `Clone` method creates a new instance of the `StartGuiding` class with the same properties and metadata as the original. This allows the guiding process to be reused or repeated in different parts of a sequence without needing to manually reconfigure each instance.
diff --git a/doc/task/guider/stop_guiding.md b/doc/task/guider/stop_guiding.md
new file mode 100644
index 00000000..5092c7bd
--- /dev/null
+++ b/doc/task/guider/stop_guiding.md
@@ -0,0 +1,87 @@
+# StopGuiding
+
+The `StopGuiding` class in the N.I.N.A. application is responsible for halting the guiding process during an astronomical imaging session. Guiding is a critical aspect of astrophotography, where a guiding camera or system keeps the telescope aligned with the target object. This class ensures that the guiding process stops correctly and validates that the guiding system is properly connected before attempting to stop guiding.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Guider`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Guider_StopGuiding_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Guider_StopGuiding_Description")]
+[ExportMetadata("Icon", "StopGuiderSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Guider")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class StopGuiding : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **guiderMediator**: An interface that handles communication with the guider hardware, specifically managing the stop guiding process.
+- **Issues**: A list of issues that are identified during the validation of the guider's connection status.
+
+### Constructor
+
+The constructor initializes the `StopGuiding` class by setting up the connection with the guider mediator, ensuring that the class can interact with the guider system to stop the guiding process.
+
+```csharp
+[ImportingConstructor]
+public StopGuiding(IGuiderMediator guiderMediator)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: Stops the guiding process using the `guiderMediator`. If any issues occur, an exception may be thrown.
+- **Validate()**: Ensures that the guiding system is connected before attempting to stop guiding. Updates the `Issues` list if any problems are found.
+- **AfterParentChanged()**: Re-validates the guider connection whenever the parent sequence item changes.
+- **Clone()**: Creates a new instance of the `StopGuiding` object, preserving its properties and metadata.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `StopGuiding` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Is Guider Connected?}
+ B -->|No| C[Throw Exception: Guider Not Connected]
+ B -->|Yes| D[Stop Guiding Process]
+ D --> E[Await Stopping Completion]
+ E --> F[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Is Guider Connected?**: The process begins by verifying that the guider is connected and ready.
+ - **No:** If the guider is not connected, an exception is thrown, aborting the process.
+ - **Yes:** If connected, the process continues to stop the guiding process.
+2. **Stop Guiding Process**: The guider is instructed to stop the guiding process.
+3. **Await Stopping Completion**: The system waits for the guiding process to stop completely.
+4. **End Execution**: The method completes execution after successfully stopping the guider.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method is the primary function of the `StopGuiding` class. It uses the `guiderMediator` to interact with the guider hardware, sending the command to stop guiding. The method ensures that the guiding process halts successfully, and if any issues arise, it handles them appropriately, potentially throwing an exception.
+
+#### `Validate` Method
+
+The `Validate` method checks that the guiding system is properly connected before allowing the guiding process to be stopped. It updates the `Issues` list with any problems that it encounters, such as the guider being disconnected. This validation is crucial to prevent errors during execution.
+
+#### `AfterParentChanged` Method
+
+The `AfterParentChanged` method is called whenever the parent sequence item changes. This triggers a re-validation of the `StopGuiding` class to ensure that any contextual changes—such as different equipment or settings—are accounted for. This helps maintain the reliability of the sequence by confirming that stopping guiding is still appropriate in the new context.
+
+#### `Clone` Method
+
+The `Clone` method creates a new instance of the `StopGuiding` class, preserving all properties and metadata from the original instance. This is useful for repeating the stop guiding process in different parts of a sequence without manually configuring each instance.
diff --git a/doc/task/interpreter.md b/doc/task/interpreter.md
new file mode 100644
index 00000000..5fff03d4
--- /dev/null
+++ b/doc/task/interpreter.md
@@ -0,0 +1,328 @@
+# TaskInterpreter Class Overview
+
+The TaskInterpreter class is part of the lithium namespace and is designed to load, manage, and execute scripts in JSON format. It provides a variety of methods to control script execution, manage variables, and handle exceptions. Below is an overview of the class and its key components.
+
+## Overall Flowchart
+
+```mermaid
+flowchart TD
+ A[TaskInterpreter]
+ A1(TaskInterpreterImpl)
+ A2(Scripts Management)
+ A3(Variables Management)
+ A4(Functions Management)
+ A5(Execution Control)
+ A6(Event Queue)
+
+ A --> A1
+ A1 --> A2
+ A1 --> A3
+ A1 --> A4
+ A1 --> A5
+ A1 --> A6
+
+ A2 --> B1[loadScript]
+ A2 --> B2[unloadScript]
+ A2 --> B3[hasScript]
+ A2 --> B4[getScript]
+ A3 --> C1[setVariable]
+ A3 --> C2[getVariable]
+ A4 --> D1[registerFunction]
+ A4 --> D2[registerExceptionHandler]
+ A5 --> E1[execute]
+ A5 --> E2[stop]
+ A5 --> E3[pause]
+ A5 --> E4[resume]
+ A5 --> E5[executeStep]
+ A6 --> F1[queueEvent]
+```
+
+### Explanation
+
+TaskInterpreterImpl: This is a private implementation class that contains the actual data structures and methods used by TaskInterpreter. It includes:
+Scripts Management: Manages loading, unloading, and checking of scripts.
+Variables Management: Manages setting and getting of variables.
+Functions Management: Handles function registration and invocation.
+Execution Control: Handles the execution flow of the scripts, including pause, stop, and resume functionalities.
+Event Queue: Manages the event queue for the interpreter.
+
+## Key Functions
+
+### `loadScript` Function
+
+```mermaid
+flowchart TD
+ A[loadScript -name, script]
+ B[Lock Mutex]
+ C[Store script in scripts_]
+ D[Unlock Mutex]
+ E[Call prepareScript - script]
+ F[Call parseLabels - script]
+ G[Exception Handling]
+
+ A --> B
+ B --> C
+ C --> D
+ D --> E
+ E --> F
+ E --> G[Exception?]
+ G -->|Yes| THROW_RUNTIME_ERROR
+ G -->|No| F
+```
+
+The loadScript function loads a script into the interpreter. It locks the mutex, stores the script in the scripts\_ map, prepares the script by processing it, and then parses any labels. If any errors occur during preparation, an exception is thrown.
+
+### `execute` Function
+
+```mermaid
+flowchart TD
+ A[execute - scriptName]
+ B[Check stopRequested_ flag]
+ C[Set isRunning_ to true]
+ D[Join existing executionThread_]
+ E[Check if script exists]
+ F[Start executionThread_]
+ G[Execute steps sequentially]
+ H[Catch exceptions]
+ I[Set isRunning_ to false]
+ J[Notify all waiting threads]
+
+ A --> B
+ B --> C
+ C --> D
+ D --> E
+ E -->|No| THROW_RUNTIME_ERROR
+ E -->|Yes| F
+ F --> G
+ G --> H[Exception?]
+ H -->|Yes| HandleException
+ H -->|No| I
+ I --> J
+```
+
+The execute function starts the execution of a specified script. It checks if the script exists, sets the isRunning\_ flag, and runs the script in a separate thread. If any exception occurs during execution, it is caught and handled appropriately. After the execution is complete, it notifies any waiting threads.
+
+### `executeStep` Function
+
+```mermaid
+flowchart TD
+ A[executeStep - step, idx, script]
+ B[Check stopRequested_ flag]
+ C[Determine step type]
+ D[Call corresponding executeX function]
+ E[Return true]
+ F[Catch exceptions]
+ G[Log error and handle exception]
+ H[Return false]
+
+ A --> B
+ B -->|Stopped| H
+ B -->|Not Stopped| C
+ C --> D
+ D --> E
+ E -->|Success| E
+ E -->|Failure| F
+ F --> G
+ G --> H
+```
+
+The executeStep function handles the execution of individual steps within a script. It checks if execution should stop, determines the step type, and calls the appropriate function to handle the step. If an exception occurs, it logs the error, handles the exception, and returns false to indicate failure.
+
+### `setVariable` Function
+
+```mermaid
+flowchart TD
+ A[setVariable - name, value, type]
+ B[Lock Mutex]
+ C[Wait for isRunning_ to be false]
+ D[Determine the type of value]
+ E[Check if type matches]
+ F[Store variable in variables_]
+ G[Unlock Mutex]
+ H[Exception Handling]
+
+ A --> B
+ B --> C
+ C --> D
+ D --> E[Type Mismatch?]
+ E -->|Yes| THROW_RUNTIME_ERROR
+ E -->|No| F
+ F --> G
+ G --> H[Exception?]
+ H -->|Yes| THROW_RUNTIME_ERROR
+ H -->|No| G
+```
+
+The setVariable function sets a variable's value and type in the interpreter. It first locks the mutex and waits until isRunning* is false. It then checks if the provided type matches the value's determined type. If the types match, it stores the variable in variables*. If any exception occurs during the process, it is thrown as a runtime error.
+
+### `executeCall` Function
+
+```mermaid
+flowchart TD
+ A[executeCall - step]
+ B[Extract functionName and params]
+ C[Evaluate params]
+ D[Check if function exists]
+ E[Call function with params]
+ F[Store result in targetVariable if specified]
+ G[Handle exceptions]
+
+ A --> B
+ B --> C
+ C --> D[Function exists?]
+ D -->|No| THROW_RUNTIME_ERROR
+ D -->|Yes| E
+ E --> F
+ F --> G
+```
+
+The executeCall function is used to execute a registered function. It extracts the function name and parameters from the step, looks up the corresponding function in the functions\_ map, and calls it. If a target variable is specified, the return value is stored in that variable.
+
+### `executeCondition` Function
+
+```mermaid
+flowchart TD
+ A[executeCondition - step, idx, script]
+ B[Evaluate condition]
+ C[Condition is true?]
+ D[Execute true block]
+ E[Execute false block if exists]
+
+ A --> B
+ B --> C
+ C -->|Yes| D
+ C -->|No| E
+```
+
+The executeCondition function evaluates a condition and executes the appropriate block of code. If the condition is true, the true block is executed; otherwise, the false block is executed (if it exists).
+
+### `executeGoto` Function
+
+```mermaid
+flowchart TD
+ A[executeGoto - step, idx, script]
+ B[Extract label]
+ C[Find label in labels_ map]
+ D[Update idx to label position]
+ E[Handle label not found]
+
+ A --> B
+ B --> C
+ C -->|Found| D
+ C -->|Not Found| E
+ E --> THROW_RUNTIME_ERROR
+```
+
+The executeGoto function allows jumping to a specific point in the script based on a label. It finds the label in the script and updates the execution index to that position.
+
+### `executeParallel` Function
+
+```mermaid
+flowchart TD
+ A[executeParallel - step, idx, script]
+ B[Create task for each step]
+ C[Enqueue tasks in taskPool]
+ D[Wait for all tasks to complete]
+ E[Return to main execution flow]
+
+ A --> B
+ B --> C
+ C --> D
+ D --> E
+```
+
+The executeParallel function executes multiple steps in parallel. It creates a task for each step, enqueues these tasks to the task pool, and waits for all tasks to complete before proceeding.
+
+### `executeTryCatch` Function
+
+```mermaid
+flowchart TD
+ A[executeTryCatch - step, idx, script]
+ B[Execute try block]
+ C[Exception occurred?]
+ D[Execute catch block]
+ E[Continue execution]
+
+ A --> B
+ B --> C
+ C -->|Yes| D
+ C -->|No| E
+ D --> E
+```
+
+The executeTryCatch function implements error handling. It executes the steps in the try block, and if an exception occurs, it handles the error by executing the steps in the catch block.
+
+### `executeAssign` Function
+
+```mermaid
+flowchart TD
+ A[executeAssign - step]
+ B[Extract variable name]
+ C[Evaluate value]
+ D[Assign value to variable]
+ E[Update variables_ map]
+
+ A --> B
+ B --> C
+ C --> D
+ D --> E
+```
+
+The executeAssign function assigns a value to a variable. It evaluates the value specified in the step and stores it in the designated variable.
+
+### `executeLoop` Function
+
+```mermaid
+flowchart TD
+ A[executeLoop - step, idx, script]
+ B[Evaluate loop count]
+ C[Start loop iteration]
+ D[Execute steps in loop]
+ E[Increment iteration counter]
+ F[Check if loop is complete]
+ G[Return to main execution flow]
+
+ A --> B
+ B --> C
+ C --> D
+ D --> E
+ E --> F
+ F -->|Complete| G
+ F -->|Not Complete| C
+```
+
+The executeLoop function handles looping in scripts. It repeats the execution of a block of steps for a specified number of iterations.
+
+### `executeSwitch` Function
+
+```mermaid
+flowchart TD
+ A[executeSwitch - step, idx, script]
+ B[Evaluate switch variable]
+ C[Match variable with case blocks]
+ D[Execute matched case block]
+ E[Execute default block if no match]
+
+ A --> B
+ B --> C
+ C -->|Matched| D
+ C -->|No Match| E
+```
+
+The executeSwitch function implements multi-branch conditional logic. It evaluates a variable and executes the corresponding case block or a default block if no cases match.
+
+### `handleException` Function
+
+```mermaid
+flowchart TD
+ A[handleException - scriptName, e]
+ B[Check if exception handler exists for script]
+ C[Call exception handler]
+ D[Log unhandled exception]
+
+ A --> B
+ B -->|Exists| C
+ B -->|Not Exists| D
+```
+
+The handleException function is called when an unhandled exception occurs during script execution. It checks for a registered exception handler and invokes it if available; otherwise, it logs the error.
diff --git a/doc/task/solver/center.md b/doc/task/solver/center.md
new file mode 100644
index 00000000..185a299f
--- /dev/null
+++ b/doc/task/solver/center.md
@@ -0,0 +1,99 @@
+# Center
+
+## Overview
+
+The `Center` sequence item in N.I.N.A. is designed to accurately center a telescope on a specific set of celestial coordinates. This process uses plate solving, a method of determining the exact position of a telescope by analyzing an image of the night sky. The `Center` class is part of the N.I.N.A. sequencer, which allows users to automate various astrophotography tasks.
+
+## Class Diagram
+
+```mermaid
+classDiagram
+ class Center {
+ - bool Inherited
+ - InputCoordinates Coordinates
+ - IList~string~ Issues
+ - IProfileService profileService
+ - ITelescopeMediator telescopeMediator
+ - IImagingMediator imagingMediator
+ - IFilterWheelMediator filterWheelMediator
+ - IGuiderMediator guiderMediator
+ - IDomeMediator domeMediator
+ - IDomeFollower domeFollower
+ - IPlateSolverFactory plateSolverFactory
+ - IWindowServiceFactory windowServiceFactory
+ + Center(profileService, telescopeMediator, imagingMediator, filterWheelMediator, guiderMediator, domeMediator, domeFollower, plateSolverFactory, windowServiceFactory)
+ + Task Execute(IProgress~ApplicationStatus~ progress, CancellationToken token)
+ + bool Validate()
+ + string ToString()
+ + object Clone()
+ }
+ Center --> IProfileService
+ Center --> ITelescopeMediator
+ Center --> IImagingMediator
+ Center --> IFilterWheelMediator
+ Center --> IGuiderMediator
+ Center --> IDomeMediator
+ Center --> IDomeFollower
+ Center --> IPlateSolverFactory
+ Center --> IWindowServiceFactory
+ Center --> InputCoordinates
+```
+
+## Key Components
+
+1. **Dependencies and Mediators**
+
+ - `IProfileService`: Provides access to the user's profile settings, which are critical for the centering process.
+ - `ITelescopeMediator`: Manages telescope operations, including slewing to the target coordinates.
+ - `IImagingMediator`: Handles the camera operations needed to capture images for plate solving.
+ - `IFilterWheelMediator`, `IGuiderMediator`, `IDomeMediator`, `IDomeFollower`: Additional equipment mediators that may be involved depending on the setup.
+ - `IPlateSolverFactory`: Generates the plate solver used to determine the exact position of the telescope.
+ - `IWindowServiceFactory`: Manages UI windows, such as the one displaying the status of the plate-solving process.
+
+2. **Attributes**
+
+ - `Coordinates`: Stores the target celestial coordinates for centering.
+ - `Issues`: A list of any issues or validation errors encountered during the centering process.
+ - `Inherited`: Indicates whether the coordinates were inherited from a parent sequence item.
+
+3. **Methods**
+ - `Execute`: The main method that performs the centering operation. It involves:
+ 1. Stopping guiding if it’s active.
+ 2. Slewing the telescope to the target coordinates.
+ 3. Initiating the plate-solving process.
+ 4. Synchronizing the dome position if necessary.
+ 5. Resuming guiding if it was stopped.
+ - `Validate`: Checks for any issues that might prevent the centering operation, such as a disconnected telescope.
+ - `Clone`: Creates a deep copy of the `Center` object.
+ - `ToString`: Provides a string representation of the sequence item, including its category and coordinates.
+
+## Process Flowchart
+
+```mermaid
+flowchart TD
+ A[Start] --> B{Is Telescope Connected?}
+ B -- Yes --> C[Slew to Coordinates]
+ C --> D{Is Dome Following Enabled?}
+ D -- No --> E[Synchronize Dome with Telescope]
+ D -- Yes --> F[Proceed with Plate Solving]
+ E --> F
+ F --> G[Capture Image]
+ G --> H[Initiate Plate Solving]
+ H --> I{Plate Solving Success?}
+ I -- Yes --> J[Complete Centering Process]
+ I -- No --> K[Retry or Fail Sequence]
+ J --> L[Resume Guiding]
+ L --> M[End]
+ B -- No --> N[Error: Telescope Not Connected]
+ N --> M
+```
+
+## Execution Flow
+
+1. **Initialization**: The `Center` class is initialized with dependencies that manage various equipment and services required for the centering process.
+2. **Validation**: Before executing the centering operation, the `Validate` method checks if the telescope is connected. If not, the process halts with an error.
+3. **Slewing**: The telescope is slewed to the target coordinates provided by the user or inherited from a parent sequence item.
+4. **Dome Synchronization**: If the observatory dome is not following the telescope, it is synchronized manually.
+5. **Plate Solving**: The process captures an image of the sky and uses plate solving to determine the exact position of the telescope.
+6. **Guiding**: If guiding was stopped earlier, it is resumed after successful centering.
+7. **Completion**: The process concludes, and any issues are logged or displayed to the user.
diff --git a/doc/task/solver/center_and_rotate.md b/doc/task/solver/center_and_rotate.md
new file mode 100644
index 00000000..a4db5c1b
--- /dev/null
+++ b/doc/task/solver/center_and_rotate.md
@@ -0,0 +1,78 @@
+# Center and Rotate
+
+This document provides an overview of the `CenterAndRotate` class from the N.I.N.A. software, which is responsible for controlling the telescope and camera to ensure accurate centering and rotation of the telescope's field of view. This functionality is crucial for astrophotography, where precise alignment and positioning are necessary.
+
+## Class Overview
+
+The `CenterAndRotate` class extends the `Center` class, adding functionality to rotate the telescope's field of view to match a desired position angle. This is particularly useful when capturing astronomical objects that require specific framing.
+
+### Key Components
+
+- **IProfileService**: Manages profile settings, such as plate solving settings and equipment configurations.
+- **ITelescopeMediator**: Handles communication with the telescope, including slewing and retrieving its current position.
+- **IImagingMediator**: Manages the imaging process, including camera control.
+- **IRotatorMediator**: Manages the rotator, which adjusts the camera's rotation angle.
+- **IFilterWheelMediator**: Controls the filter wheel for selecting the appropriate filter during imaging.
+- **IGuiderMediator**: Handles the guiding process, which keeps the telescope locked on the target.
+- **IDomeMediator & IDomeFollower**: Synchronizes the dome with the telescope’s movements.
+- **IPlateSolverFactory**: Creates instances of plate solvers, which are used to determine the telescope's position based on star field images.
+- **IWindowServiceFactory**: Provides a service to display windows for user interaction, such as progress tracking.
+
+### Properties
+
+- **PositionAngle**: The desired rotation angle of the telescope's field of view.
+- **Coordinates**: The target celestial coordinates to which the telescope should point.
+
+### Methods
+
+- **Execute**: The main method that centers the telescope on the target and adjusts the field of view rotation.
+- **Solve**: Performs a plate solve to determine the telescope's current position and orientation.
+- **Validate**: Checks if all necessary equipment (e.g., telescope, rotator) is connected and ready.
+- **AfterParentChanged**: Updates the target coordinates and position angle based on the parent sequence item.
+
+## Detailed Workflow with Flowchart
+
+Below is a detailed explanation of how the `CenterAndRotate` class operates, accompanied by a flowchart for visual reference.
+
+1. **Initialization**
+
+ - The `CenterAndRotate` class is instantiated with various mediators and services that manage telescope, rotator, and other equipment.
+
+2. **Execution (`Execute` Method)**
+
+ - The method begins by checking if the telescope is parked. If parked, an error is raised.
+ - The telescope slews to the specified coordinates.
+ - The dome is synchronized with the telescope if necessary.
+ - The `Solve` method is called to perform a plate solve and determine the telescope’s current orientation.
+ - The rotator is adjusted to match the desired position angle. If the difference between the current and desired angles is greater than a specified tolerance, the rotator moves accordingly.
+ - Once the rotation is within tolerance, the `DoCenter` method (inherited from `Center`) is called to fine-tune the telescope’s positioning.
+
+3. **Plate Solving (`Solve` Method)**
+
+ - The method creates a plate solver instance using `IPlateSolverFactory`.
+ - A series of images are captured, and the solver compares them with star catalogs to determine the telescope’s exact position and orientation.
+ - The solver adjusts the telescope’s position until the target coordinates and rotation angle are achieved.
+
+4. **Validation (`Validate` Method)**
+
+ - Checks if the telescope and rotator are connected.
+ - If any issues are detected, they are reported, and execution is halted.
+
+5. **Parent Change Handling (`AfterParentChanged` Method)**
+ - When the parent sequence item changes, the method updates the target coordinates and position angle based on the new parent’s context.
+
+```mermaid
+flowchart TD
+ A[Initialize CenterAndRotate] --> B[Check Telescope Parked Status]
+ B -- Not Parked --> C[Slew to Target Coordinates]
+ C --> D[Synchronize Dome with Telescope]
+ D --> E[Perform Plate Solve]
+ E --> F[Determine Rotation Adjustment Needed]
+ F -- Rotation Needed --> G[Move Rotator to Target Angle]
+ G --> H[Is Rotation within Tolerance?]
+ H -- No --> F
+ H -- Yes --> I[Perform Final Centering DoCenter Method]
+ I --> J[Resume Guiding if stopped]
+ J --> K[Execution Complete]
+ B -- Parked --> L[Raise Error: Telescope is Parked]
+```
diff --git a/doc/task/solver/solve_and_async.md b/doc/task/solver/solve_and_async.md
new file mode 100644
index 00000000..2be9c353
--- /dev/null
+++ b/doc/task/solver/solve_and_async.md
@@ -0,0 +1,104 @@
+# SolveAndSync
+
+The `SolveAndSync` class in the N.I.N.A. application is designed to accurately synchronize the telescope's position with the actual celestial coordinates by performing a plate solving process. This class is essential for ensuring the telescope is correctly aligned with the intended target during an imaging session.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Platesolving`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.PlateSolving`
+ - `NINA.Profile.Interfaces`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Utility.WindowService`
+ - `NINA.ViewModel`
+ - `NINA.Core.Locale`
+ - `NINA.Equipment.Model`
+ - `NINA.WPF.Base.ViewModel`
+ - `NINA.PlateSolving.Interfaces`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Platesolving_SolveAndSync_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Platesolving_SolveAndSync_Description")]
+[ExportMetadata("Icon", "CrosshairSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SolveAndSync : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **PlateSolveStatusVM**: Manages the status of the plate-solving process, displaying progress and results.
+- **Issues**: A list of issues found during the validation of the class, particularly related to equipment connectivity.
+
+### Constructor
+
+The constructor initializes the `SolveAndSync` class with dependencies on various services and mediators, including those for the telescope, rotator, imaging, filter wheel, plate solver, and window service.
+
+```csharp
+[ImportingConstructor]
+public SolveAndSync(IProfileService profileService, ...)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: This method executes the main logic of the `SolveAndSync` class. It performs plate solving and synchronizes the telescope’s position with the solved coordinates.
+- **DoSolve(IProgress progress, CancellationToken token)**: This method performs the actual plate solving using the configured settings.
+- **Validate()**: Checks if the telescope is connected and operational before attempting to solve and sync.
+- **Clone()**: Creates a deep copy of the `SolveAndSync` object.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `SolveAndSync` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Create Window Service]
+ B --> C[Show PlateSolveStatusVM Window]
+ C --> D[Start Plate Solving]
+ D --> E{Solving Successful?}
+ E -->|No| F[Throw Exception: Plate Solve Failed]
+ E -->|Yes| G[Sync Telescope with Coordinates]
+ G --> H[Sync Rotator with Position Angle]
+ H --> I{Sync Successful?}
+ I -->|No| J[Throw Exception: Sync Failed]
+ I -->|Yes| K[Proceed with Imaging Sequence]
+ K --> L[Close PlateSolveStatusVM Window]
+ L --> M[End]
+```
+
+### Flowchart Explanation
+
+1. **Create Window Service:** Initializes a window service to display the status of the plate-solving process.
+2. **Show PlateSolveStatusVM Window:** Displays the `PlateSolveStatusVM` window to provide real-time feedback on the plate-solving progress.
+3. **Start Plate Solving:** Begins the process of solving the telescope’s current position using the plate solver.
+4. **Solving Successful?:** Checks if the plate-solving process was successful.
+ - **No:** Throws an exception indicating that the plate solve failed.
+ - **Yes:** Proceeds to sync the telescope’s coordinates.
+5. **Sync Telescope with Coordinates:** Synchronizes the telescope's internal coordinates with the solved celestial coordinates.
+6. **Sync Rotator with Position Angle:** Syncs the rotator's position angle with the orientation derived from the plate-solving result.
+7. **Sync Successful?:** Checks if the telescope sync was successful.
+ - **No:** Throws an exception indicating that the sync operation failed.
+ - **Yes:** Proceeds with the imaging sequence.
+8. **Close PlateSolveStatusVM Window:** Closes the status window after a short delay.
+9. **End:** The method concludes.
+
+### Detailed Method Descriptions
+
+#### `Execute` Method
+
+The `Execute` method is the core of the `SolveAndSync` class, responsible for initiating and managing the entire plate-solving and synchronization process. It uses the `PlateSolveStatusVM` to provide real-time updates on the solving process and handles the synchronization of the telescope and rotator.
+
+#### `DoSolve` Method
+
+The `DoSolve` method encapsulates the logic for performing the actual plate-solving operation. It retrieves the appropriate plate solver and blind solver, configures the necessary parameters, and executes the solving sequence to determine the telescope's precise position and orientation.
+
+#### `Validate` Method
+
+The `Validate` method checks if the telescope is connected and functional before proceeding with the solve-and-sync operation. It ensures that the necessary equipment is ready, preventing runtime errors and providing feedback through the `Issues` list.
diff --git a/doc/task/solver/solve_and_rotate.md b/doc/task/solver/solve_and_rotate.md
new file mode 100644
index 00000000..c53d1b43
--- /dev/null
+++ b/doc/task/solver/solve_and_rotate.md
@@ -0,0 +1,95 @@
+# SolveAndRotate
+
+The `SolveAndRotate` class is part of the N.I.N.A. application, which is used for astrophotography and astronomical imaging. This class is responsible for solving the position of a telescope and rotating it to achieve a desired position angle. The class integrates various services and mediators to interact with the telescope, rotator, and other imaging equipment.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Platesolving`
+- **Dependencies:**
+ - `NINA.Astrometry`
+ - `NINA.Core.Locale`
+ - `NINA.Core.Model`
+ - `NINA.Core.Utility`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.PlateSolving`
+ - `NINA.Profile.Interfaces`
+ - `NINA.Sequencer.Utility`
+ - `NINA.Sequencer.Validations`
+ - `NINA.WPF.Base.ViewModel`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Platesolving_SolveAndRotate_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Platesolving_SolveAndRotate_Description")]
+[ExportMetadata("Icon", "PlatesolveAndRotateSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Rotator")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SolveAndRotate : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **PositionAngle**: This property holds the desired position angle for the telescope. It ensures the value is within a valid range (0-360 degrees).
+- **Inherited**: Indicates whether the position angle is inherited from a parent sequence item.
+- **Issues**: A list of validation issues that might arise during execution.
+- **PlateSolveStatusVM**: Manages the status of the plate solving process.
+
+### Constructor
+
+The constructor initializes the `SolveAndRotate` class with dependencies on services and mediators for the telescope, imaging, rotator, filter wheel, guider, plate solver, and window service.
+
+```csharp
+[ImportingConstructor]
+public SolveAndRotate(IProfileService profileService, ...)
+```
+
+### Key Methods
+
+- **Execute(IProgress progress, CancellationToken token)**: This method executes the main logic of the `SolveAndRotate` class. It orchestrates the process of plate solving, rotating, and validating the rotation against the desired position angle.
+- **Solve(IProgress progress, CancellationToken token)**: This method performs the plate solving using the configured settings.
+- **AfterParentChanged()**: Updates the position angle and inheritance status based on the parent sequence item.
+- **Validate()**: Checks if the necessary components (e.g., rotator) are connected and operational.
+
+### Flowchart: Execution Process
+
+Below is a flowchart that outlines the key steps in the `Execute` method of the `SolveAndRotate` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Stop Guiding]
+ B --> C[Initialize Rotation]
+ C --> D{Within Tolerance?}
+ D -->|Yes| E[Exit Loop]
+ D -->|No| F[Solve Position]
+ F --> G{Solve Success?}
+ G -->|Yes| H[Sync Rotator with Orientation]
+ G -->|No| I[Throw Exception]
+ H --> J[Calculate Rotation Distance]
+ J --> K[Move Rotator Relatively]
+ K --> D
+ E --> L[Resume Guiding]
+ L --> M[Close Service]
+ M --> N[End]
+```
+
+### Flowchart Explanation
+
+1. **Stop Guiding:** The guider is stopped to prepare for the rotation process.
+2. **Initialize Rotation:** The initial rotation distance is set to a maximum value.
+3. **Within Tolerance?:** Checks if the current rotation is within the acceptable tolerance.
+ - **Yes:** Exit the loop and proceed to resume guiding.
+ - **No:** Continue with the solving and rotation process.
+4. **Solve Position:** The telescope’s current position is solved to determine the orientation.
+5. **Solve Success?:** Checks if the solving process was successful.
+ - **Yes:** Sync the rotator with the current orientation.
+ - **No:** Throw an exception indicating the failure of the solving process.
+6. **Calculate Rotation Distance:** The distance to the target rotation angle is calculated.
+7. **Move Rotator Relatively:** The rotator is moved by the calculated rotation distance.
+8. **Repeat:** The process loops until the rotation is within the desired tolerance.
+9. **Resume Guiding:** Guiding is resumed after the rotation is completed.
+10. **Close Service:** The window service is closed with a delay.
+11. **End:** The method concludes.
diff --git a/doc/task/switch/switch.md b/doc/task/switch/switch.md
new file mode 100644
index 00000000..70399650
--- /dev/null
+++ b/doc/task/switch/switch.md
@@ -0,0 +1,97 @@
+# SetSwitchValue
+
+The `SetSwitchValue` class is designed to interact with switches within the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application. It allows for setting values on writable switches and is used within sequence operations.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Switch`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Core.Utility`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+ - `NINA.Equipment.Interfaces`
+ - `NINA.Equipment.Equipment.MySwitch`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Switch_SetSwitchValue_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Switch_SetSwitchValue_Description")]
+[ExportMetadata("Icon", "ButtonSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Switch")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SetSwitchValue : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **switchMediator**: Interface for communicating with the switch hardware.
+- **issues**: List of validation issues encountered.
+- **Value**: The value to set on the switch.
+- **SwitchIndex**: Index of the switch to be controlled.
+- **SelectedSwitch**: The currently selected writable switch.
+- **WritableSwitches**: List of writable switches available.
+
+### Constructor
+
+The constructor initializes the `SetSwitchValue` class with the provided `switchMediator` and sets up a dummy list of switches.
+
+```csharp
+[ImportingConstructor]
+public SetSwitchValue(ISwitchMediator switchMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `SetSwitchValue` instance.
+- **Execute(IProgress progress, CancellationToken token)**: Sets the switch value using `switchMediator`.
+- **CreateDummyList()**: Creates a dummy list of switches for testing purposes.
+- **Validate()**: Checks if the switch is connected and validates the switch value.
+- **ToString()**: Provides a string representation of the `SetSwitchValue` instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `SetSwitchValue` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Set Switch Value]
+ B --> C{Value Set Successfully?}
+ C -- No --> D[Handle Error]
+ C -- Yes --> E[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Set Switch Value**: Calls `switchMediator.SetSwitchValue()` to set the value on the switch.
+2. **Value Set Successfully?**: Checks if the value was set successfully. If not, handles the error accordingly.
+3. **End Execution**: If successful, the method completes without errors.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `SetSwitchValue` class with the same configuration as the current instance, including the switch index and value.
+
+#### `Execute`
+
+Uses `switchMediator.SetSwitchValue()` to set the value on the switch at the specified index.
+
+#### `CreateDummyList`
+
+Generates a dummy list of switches, which is useful for scenarios where the actual switch hardware is not connected.
+
+#### `Validate`
+
+1. **Check Connection**: Verifies if the switch is connected. If not, replaces the real list with a dummy list.
+2. **Update List**: If the switch is connected, updates the list of writable switches.
+3. **Validation**: Ensures that the selected switch and value are valid. Adds errors to the issues list if validation fails.
+
+#### `ToString`
+
+Provides a string representation of the `SetSwitchValue` instance, including the category, item name, switch index, and value.
diff --git a/doc/task/task_list.md b/doc/task/task_list.md
new file mode 100644
index 00000000..fdc91695
--- /dev/null
+++ b/doc/task/task_list.md
@@ -0,0 +1,83 @@
+# NINA Task List
+
+This is the task list from NINA and we need to enhance it.
+
+## Camera
+
+### Cool Camera
+
+
++ Warm Camera [minimum duration]
++ Dew Heater [on/off]
++ Set Readout Mode
++ Take Exposure
++ Take Many Exposures
++ Take Subframe Exposure
++ Smart Exposure
+
+## Dome
+
++ Close Dome Shutter
++ Enable Dome Sync
++ Disable Dome Sync
++ Open Dome Shutter
++ Park Dome
++ Slew Dome Azimuth
++ Synchronize Dome
++ Filter Wheel
++ Switch Filter
++ Flat Panel
++ Close Flat Panel Cover
++ Open Flat Panel Cover
++ Set Brightness
++ Toggle Light
++ Trained Flat Exposure
++ Trained Dark Exposure
+
+## Focuser
+
++ Move Focuser
++ Move Focuser By Temp.
++ Move Focuser Relative
++ Run Autofocus
+
+## Guider
+
++ Dither
++ Start Guiding
++ Stop Guiding
+
+## Rotator
+
++ Rotate By Mechanical Angle
++ Solve and Rotate
++ Safety Monitor
++ Wait Until Safe
+
+## Switch
+
++ Set Switch Value
+
+## Telescope
+
++ Find Home
++ Park Scope
++ Set Tracking
++ Slew And Center
++ Slew To Alt/Az
++ Slew To Ra/Dec
++ Slew, Center And Rotate
++ Solve And Sync
++ Unpark Scope
+
+## Utility
+
++ Annotation
++ External Script
++ Message Box
++ Wait For Altitude
++ Wait For Time
++ Wait For Time Span
++ Wait If Moon Altitude
++ Wait If Sun Altitude
++ Wait Until Above Horizon
diff --git a/doc/task/telescope/find_home.md b/doc/task/telescope/find_home.md
new file mode 100644
index 00000000..417f7be3
--- /dev/null
+++ b/doc/task/telescope/find_home.md
@@ -0,0 +1,96 @@
+# FindHome
+
+The `FindHome` class is used for directing a telescope to find its home position. It interacts with both the telescope and guider mediators to ensure the telescope returns to its home position while stopping any ongoing guiding operations.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Telescope`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Telescope_FindHome_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Telescope_FindHome_Description")]
+[ExportMetadata("Icon", "HomeSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class FindHome : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **telescopeMediator**: Manages communication with the telescope hardware.
+- **guiderMediator**: Manages communication with the guider hardware.
+- **issues**: A list to capture any validation issues.
+
+### Constructor
+
+The constructor initializes the `FindHome` class with `telescopeMediator` and `guiderMediator`.
+
+```csharp
+[ImportingConstructor]
+public FindHome(ITelescopeMediator telescopeMediator, IGuiderMediator guiderMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `FindHome` instance.
+- **Execute(IProgress progress, CancellationToken token)**: Commands the telescope to find its home position while stopping guiding.
+- **Validate()**: Checks if the telescope is connected and if it supports finding the home position.
+- **AfterParentChanged()**: Revalidates the state when the parent changes.
+- **ToString()**: Returns a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `FindHome` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Stop Guiding]
+ B --> C[Find Telescope Home]
+ C --> D[Await Home Finding Completion]
+ D --> E[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Stop Guiding**: Stops any ongoing guiding operations using `guiderMediator`.
+2. **Find Telescope Home**: Commands the telescope to find its home position using `telescopeMediator`.
+3. **Await Home Finding Completion**: Waits for the telescope to complete the home finding process.
+4. **End Execution**: Marks the end of the execution process.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `FindHome` class with the same configuration as the current instance.
+
+#### `Execute`
+
+1. **Stop Guiding**: Stops any guiding operation to avoid conflicts.
+2. **Find Telescope Home**: Directs the telescope to locate its home position. This operation might involve moving the telescope to a known reference point where it can determine its home position.
+3. **Await Completion**: Waits until the telescope completes the home finding process.
+
+#### `Validate`
+
+Checks the current state of the telescope:
+
+- If the telescope is not connected, adds an error to the issues list.
+- If the telescope cannot find its home position, adds an error to the issues list.
+- Updates the `Issues` property with any validation errors.
+
+#### `AfterParentChanged`
+
+Revalidates the state of the `FindHome` instance whenever its parent changes to ensure it remains valid.
+
+#### `ToString`
+
+Provides a string representation of the `FindHome` instance, including the category and item name.
diff --git a/doc/task/telescope/park.md b/doc/task/telescope/park.md
new file mode 100644
index 00000000..61803a97
--- /dev/null
+++ b/doc/task/telescope/park.md
@@ -0,0 +1,94 @@
+# ParkScope
+
+The `ParkScope` class is designed for parking a telescope and stopping any ongoing guiding operations. It integrates with both telescope and guider mediators to ensure the telescope is safely parked.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Telescope`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Telescope_ParkScope_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Telescope_ParkScope_Description")]
+[ExportMetadata("Icon", "ParkSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class ParkScope : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **telescopeMediator**: Handles communication with the telescope hardware.
+- **guiderMediator**: Manages communication with the guider hardware.
+- **issues**: A list to record any validation issues.
+
+### Constructor
+
+The constructor initializes the `ParkScope` class with `telescopeMediator` and `guiderMediator`.
+
+```csharp
+[ImportingConstructor]
+public ParkScope(ITelescopeMediator telescopeMediator, IGuiderMediator guiderMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `ParkScope` instance.
+- **Execute(IProgress progress, CancellationToken token)**: Commands the telescope to park and stops guiding.
+- **Validate()**: Checks if the telescope is connected.
+- **AfterParentChanged()**: Revalidates the state when the parent changes.
+- **ToString()**: Returns a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `ParkScope` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Stop Guiding]
+ B --> C[Park Telescope]
+ C --> D[Handle Failure]
+ D --> E[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Stop Guiding**: Stops any ongoing guiding operation using `guiderMediator`.
+2. **Park Telescope**: Commands the telescope to park using `telescopeMediator`. If this operation fails, an exception is thrown.
+3. **Handle Failure**: If the telescope fails to park, a `SequenceEntityFailedException` is thrown.
+4. **End Execution**: Marks the end of the execution process.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `ParkScope` class with the same configuration as the current instance.
+
+#### `Execute`
+
+1. **Stop Guiding**: Calls `guiderMediator.StopGuiding()` to halt any ongoing guiding operations.
+2. **Park Telescope**: Uses `telescopeMediator.ParkTelescope()` to park the telescope. If the parking operation is unsuccessful, an exception is thrown.
+
+#### `Validate`
+
+Checks the current state of the telescope:
+
+- If the telescope is not connected, adds an error to the issues list.
+- Updates the `Issues` property with any validation errors.
+
+#### `AfterParentChanged`
+
+Revalidates the state of the `ParkScope` instance whenever its parent changes to ensure it remains valid.
+
+#### `ToString`
+
+Provides a string representation of the `ParkScope` instance, including the category and item name.
diff --git a/doc/task/telescope/set_tracking.md b/doc/task/telescope/set_tracking.md
new file mode 100644
index 00000000..cfa96198
--- /dev/null
+++ b/doc/task/telescope/set_tracking.md
@@ -0,0 +1,104 @@
+# SetTracking
+
+The `SetTracking` class is responsible for setting the tracking mode of a telescope. It provides functionality to select and apply various tracking modes, ensuring that the telescope operates correctly according to the selected mode.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Telescope`
+- **Dependencies:**
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Core.Locale`
+ - `NINA.Equipment.Interfaces`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Telescope_SetTracking_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Telescope_SetTracking_Description")]
+[ExportMetadata("Icon", "SpeedometerSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SetTracking : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **telescopeMediator**: Interface for interacting with the telescope hardware.
+- **issues**: List of validation issues.
+- **trackingMode**: The current tracking mode selected for the telescope.
+
+### Static Properties
+
+- **trackingModeChoices**: A static list of available tracking modes.
+
+### Constructor
+
+The constructor initializes the `SetTracking` class with `telescopeMediator`.
+
+```csharp
+[ImportingConstructor]
+public SetTracking(ITelescopeMediator telescopeMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `SetTracking` instance.
+- **Execute(IProgress progress, CancellationToken token)**: Sets the tracking mode on the telescope.
+- **Validate()**: Checks if the telescope is connected and if the selected tracking mode is supported.
+- **AfterParentChanged()**: Revalidates the state when the parent changes.
+- **ToString()**: Provides a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `SetTracking` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Set Tracking Mode]
+ B --> C[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Set Tracking Mode**: Uses `telescopeMediator.SetTrackingMode()` to apply the selected tracking mode.
+2. **End Execution**: Marks the end of the execution process.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `SetTracking` class with the same configuration as the current instance.
+
+#### `Execute`
+
+Sets the tracking mode on the telescope using `telescopeMediator.SetTrackingMode()`. This method completes immediately as it does not need to await any asynchronous operations.
+
+#### `Validate`
+
+Checks if the telescope is connected and if it supports the selected tracking mode:
+
+- Adds an error to the issues list if the telescope is not connected.
+- Adds an error if the selected tracking mode is not supported by the telescope.
+
+#### `AfterParentChanged`
+
+Revalidates the state of the `SetTracking` instance whenever its parent changes to ensure it remains valid.
+
+#### `ToString`
+
+Provides a string representation of the `SetTracking` instance, including the category, item name, and the selected tracking mode.
+
+### Tracking Modes
+
+The `trackingModeChoices` static property provides a list of available tracking modes:
+
+- **Sidereal**: Follows the sidereal rate of the stars.
+- **King**: A mode for specific astronomical calculations.
+- **Solar**: Tracks the sun.
+- **Lunar**: Tracks the moon.
+- **Stopped**: Disables tracking.
diff --git a/doc/task/telescope/slew_azalt.md b/doc/task/telescope/slew_azalt.md
new file mode 100644
index 00000000..08b2c3b8
--- /dev/null
+++ b/doc/task/telescope/slew_azalt.md
@@ -0,0 +1,106 @@
+# SlewScopeToAltAz
+
+The `SlewScopeToAltAz` class is designed to move a telescope to a specific altitude and azimuth position. It handles the calculation of the telescope's new position based on input coordinates and interacts with both the telescope and guider systems.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Telescope`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Profile.Interfaces`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Astrometry`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+ - `NINA.Core.Utility.Notification`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Telescope_SlewScopeToAltAz_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Telescope_SlewScopeToAltAz_Description")]
+[ExportMetadata("Icon", "SlewToAltAzSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SlewScopeToAltAz : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **profileService**: Service for accessing and managing profile-related data.
+- **telescopeMediator**: Interface for communicating with the telescope hardware.
+- **guiderMediator**: Interface for managing the guiding system.
+- **Coordinates**: The target altitude and azimuth coordinates for the telescope.
+- **issues**: List of validation issues.
+
+### Constructor
+
+The constructor initializes the `SlewScopeToAltAz` class with the provided services and sets up an event handler for profile location changes.
+
+```csharp
+[ImportingConstructor]
+public SlewScopeToAltAz(IProfileService profileService, ITelescopeMediator telescopeMediator, IGuiderMediator guiderMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `SlewScopeToAltAz` instance with the same configuration.
+- **Execute(IProgress progress, CancellationToken token)**: Moves the telescope to the specified coordinates, handling any necessary guiding operations.
+- **AfterParentChanged()**: Revalidates the state when the parent changes.
+- **Validate()**: Checks if the telescope is connected and ready.
+- **ToString()**: Provides a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `SlewScopeToAltAz` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Telescope Parked?}
+ B -- Yes --> C[Show Error and Abort]
+ B -- No --> D[Stop Guiding]
+ D --> E[Slew to Coordinates]
+ E --> F{Guiding Stopped?}
+ F -- Yes --> G[Start Guiding]
+ G --> H[End Execution]
+ F -- No --> H
+```
+
+### Flowchart Explanation
+
+1. **Telescope Parked?**: Checks if the telescope is parked. If it is, an error message is shown, and the operation is aborted.
+2. **Stop Guiding**: Stops the guiding process to prepare for the slewing operation.
+3. **Slew to Coordinates**: Moves the telescope to the specified altitude and azimuth coordinates.
+4. **Guiding Stopped?**: Checks if guiding was stopped. If it was, guiding is restarted.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `SlewScopeToAltAz` class with the same coordinates and configuration as the current instance.
+
+#### `Execute`
+
+1. **Check Telescope Status**: If the telescope is parked, an error is shown, and the method throws an exception.
+2. **Stop Guiding**: Stops the guiding process to prevent conflicts during the slewing operation.
+3. **Slew to Coordinates**: Uses `telescopeMediator.SlewToCoordinatesAsync()` to move the telescope to the target coordinates.
+4. **Restart Guiding**: If guiding was stopped, it restarts guiding to resume normal operations.
+
+#### `AfterParentChanged`
+
+Revalidates the instance whenever its parent changes to ensure it remains in a valid state.
+
+#### `Validate`
+
+Checks if the telescope is connected. If it is not, an error is added to the issues list.
+
+#### `ToString`
+
+Provides a string representation of the `SlewScopeToAltAz` instance, including the category, item name, and the target coordinates.
+
+### Coordinates
+
+- **Coordinates**: Represents the altitude and azimuth coordinates to which the telescope should move.
diff --git a/doc/task/telescope/slew_radec.md b/doc/task/telescope/slew_radec.md
new file mode 100644
index 00000000..e7329411
--- /dev/null
+++ b/doc/task/telescope/slew_radec.md
@@ -0,0 +1,111 @@
+# SlewScopeToRaDec
+
+The `SlewScopeToRaDec` class is responsible for moving the telescope to a specified right ascension (RA) and declination (Dec) coordinate. It handles the slewing operation and interacts with both the telescope and guiding systems, and supports context-based coordinate retrieval from its parent container.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Telescope`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Container`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Astrometry`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+ - `NINA.Core.Utility.Notification`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Telescope_SlewScopeToRaDec_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Telescope_SlewScopeToRaDec_Description")]
+[ExportMetadata("Icon", "SlewToRaDecSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class SlewScopeToRaDec : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **telescopeMediator**: Interface for communicating with the telescope hardware.
+- **guiderMediator**: Interface for managing the guiding system.
+- **inherited**: Indicates if coordinates are inherited from the parent context.
+- **Coordinates**: The target right ascension and declination coordinates.
+- **issues**: List of validation issues.
+
+### Constructor
+
+The constructor initializes the `SlewScopeToRaDec` class with the provided telescope and guider mediators. It also initializes the `Coordinates` property.
+
+```csharp
+[ImportingConstructor]
+public SlewScopeToRaDec(ITelescopeMediator telescopeMediator, IGuiderMediator guiderMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `SlewScopeToRaDec` instance with the same coordinates and configuration.
+- **Execute(IProgress progress, CancellationToken token)**: Moves the telescope to the specified RA and Dec coordinates, handling any necessary guiding operations.
+- **AfterParentChanged()**: Updates the coordinates if inherited from the parent context and revalidates the state.
+- **RetrieveContextCoordinates(ISequenceContainer parent)**: Recursively retrieves coordinates from the parent container if available.
+- **Validate()**: Checks if the telescope is connected and ready.
+- **ToString()**: Provides a string representation of the class instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `SlewScopeToRaDec` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B{Telescope Parked?}
+ B -- Yes --> C[Show Error and Abort]
+ B -- No --> D[Stop Guiding]
+ D --> E[Slew to Coordinates]
+ E --> F{Guiding Stopped?}
+ F -- Yes --> G[Start Guiding]
+ G --> H[End Execution]
+ F -- No --> H
+```
+
+### Flowchart Explanation
+
+1. **Telescope Parked?**: Checks if the telescope is parked. If it is, an error message is shown, and the operation is aborted.
+2. **Stop Guiding**: Stops the guiding process to prepare for the slewing operation.
+3. **Slew to Coordinates**: Uses `telescopeMediator.SlewToCoordinatesAsync()` to move the telescope to the target RA and Dec coordinates.
+4. **Guiding Stopped?**: Checks if guiding was stopped. If it was, guiding is restarted to resume normal operations.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `SlewScopeToRaDec` class with the same coordinates and configuration as the current instance.
+
+#### `Execute`
+
+1. **Check Telescope Status**: If the telescope is parked, an error is shown, and the method throws an exception.
+2. **Stop Guiding**: Stops the guiding process to avoid conflicts during the slewing operation.
+3. **Slew to Coordinates**: Uses `telescopeMediator.SlewToCoordinatesAsync()` to move the telescope to the specified RA and Dec coordinates.
+4. **Restart Guiding**: If guiding was stopped, it restarts guiding to ensure normal operations continue.
+
+#### `AfterParentChanged`
+
+Updates the `Coordinates` property if the coordinates are inherited from the parent container. It also sets the `Inherited` flag and revalidates the instance.
+
+#### `RetrieveContextCoordinates`
+
+Recursively searches for the coordinates in the parent container, allowing for context-based retrieval of coordinates if the current instance does not have them.
+
+#### `Validate`
+
+Checks if the telescope is connected. If it is not, an error is added to the issues list.
+
+#### `ToString`
+
+Provides a string representation of the `SlewScopeToRaDec` instance, including the category, item name, and target coordinates.
+
+### Coordinates
+
+- **Coordinates**: Represents the right ascension and declination coordinates to which the telescope should move.
diff --git a/doc/task/telescope/unpark.md b/doc/task/telescope/unpark.md
new file mode 100644
index 00000000..3df39cbd
--- /dev/null
+++ b/doc/task/telescope/unpark.md
@@ -0,0 +1,89 @@
+# UnparkScope
+
+The `UnparkScope` class is designed to handle the process of unparking the telescope. This class interacts with the telescope system to bring the telescope out of the parked state and is used in sequence operations within the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application.
+
+## Class Overview
+
+### Namespace
+
+- **Namespace:** `NINA.Sequencer.SequenceItem.Telescope`
+- **Dependencies:**
+ - `NINA.Core.Model`
+ - `NINA.Sequencer.Validations`
+ - `NINA.Equipment.Interfaces.Mediator`
+ - `NINA.Core.Locale`
+
+### Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Telescope_UnparkScope_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Telescope_UnparkScope_Description")]
+[ExportMetadata("Icon", "UnparkSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Telescope")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class UnparkScope : SequenceItem, IValidatable
+```
+
+### Class Properties
+
+- **telescopeMediator**: Interface for communicating with the telescope hardware.
+- **issues**: List of validation issues encountered.
+
+### Constructor
+
+The constructor initializes the `UnparkScope` class with the provided `telescopeMediator`.
+
+```csharp
+[ImportingConstructor]
+public UnparkScope(ITelescopeMediator telescopeMediator)
+```
+
+### Key Methods
+
+- **Clone()**: Creates a copy of the `UnparkScope` instance.
+- **Execute(IProgress progress, CancellationToken token)**: Unparks the telescope using `telescopeMediator`.
+- **Validate()**: Checks if the telescope is connected and sets any validation issues.
+- **AfterParentChanged()**: Revalidates the state when the parent changes.
+- **ToString()**: Provides a string representation of the `UnparkScope` instance.
+
+### Flowchart: Execution Process
+
+Below is a flowchart illustrating the key steps in the `Execute` method of the `UnparkScope` class.
+
+```mermaid
+flowchart TD
+ A[Start Execute Method] --> B[Unpark Telescope]
+ B --> C{Unparking Successful?}
+ C -- No --> D[Throw Exception]
+ C -- Yes --> E[End Execution]
+```
+
+### Flowchart Explanation
+
+1. **Unpark Telescope**: Calls `telescopeMediator.UnparkTelescope()` to unpark the telescope.
+2. **Unparking Successful?**: Checks if the unparking was successful. If not, an exception is thrown.
+3. **End Execution**: If successful, the method completes without errors.
+
+### Detailed Method Descriptions
+
+#### `Clone`
+
+Creates a new instance of the `UnparkScope` class with the same configuration as the current instance.
+
+#### `Execute`
+
+1. **Unpark Telescope**: Uses `telescopeMediator.UnparkTelescope()` to unpark the telescope.
+2. **Check Success**: If the unparking operation fails, an exception (`SequenceEntityFailedException`) is thrown.
+
+#### `Validate`
+
+Checks if the telescope is connected by querying `telescopeMediator.GetInfo()`. If not connected, adds an error message to the issues list.
+
+#### `AfterParentChanged`
+
+Revalidates the `UnparkScope` instance when its parent changes, ensuring that the state is still valid.
+
+#### `ToString`
+
+Provides a string representation of the `UnparkScope` instance, including the category and item name.
diff --git a/doc/task/utility/external_script.md b/doc/task/utility/external_script.md
new file mode 100644
index 00000000..cec9938e
--- /dev/null
+++ b/doc/task/utility/external_script.md
@@ -0,0 +1,148 @@
+# ExternalScrip
+
+The `ExternalScript` class is part of the `NINA.Sequencer.SequenceItem.Utility` namespace and is designed to execute an external script or command as part of a sequence item.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Utility_ExternalScript_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Utility_ExternalScript_Description")]
+[ExportMetadata("Icon", "ScriptSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Utility")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class ExternalScript : SequenceItem, IValidatable
+```
+
+## Properties
+
+### `OpenDialogCommand`
+
+- **Type:** `System.Windows.Input.ICommand`
+- **Description:** Command to open a file dialog for selecting the script to execute.
+
+### `Issues`
+
+- **Type:** `IList`
+- **Description:** List of validation issues.
+- **Json Property:** `[JsonProperty]`
+
+### `Script`
+
+- **Type:** `string`
+- **Description:** Path to the external script or command to be executed.
+- **Json Property:** `[JsonProperty]`
+
+## Constructors
+
+### Default Constructor
+
+```csharp
+public ExternalScript()
+```
+
+- **Description:** Initializes the command to open a file dialog for selecting the script.
+
+### Clone Constructor
+
+```csharp
+private ExternalScript(ExternalScript cloneMe) : this()
+```
+
+- **Parameters:**
+ - `cloneMe`: The instance to clone.
+
+## Methods
+
+### `Clone`
+
+```csharp
+public override object Clone()
+```
+
+- **Description:** Creates a deep copy of the current `ExternalScript` instance.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Clone Method] --> B[Create New ExternalScript]
+ B --> C[Copy Properties]
+ C --> D[Return New Instance]
+ D --> E[End]
+```
+
+### `Execute`
+
+```csharp
+public override async Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Executes the external script or command and reports progress.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[Prepare External Command]
+ B --> C[Run External Command]
+ C --> D[Check Success]
+ D -- Success --> E[Complete]
+ D -- Failure --> F[Throw Exception]
+ E --> G[End]
+ F --> G
+```
+
+### `Validate`
+
+```csharp
+public bool Validate()
+```
+
+- **Description:** Validates if the script or command exists and is executable.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Validate Method] --> B[Check Command Exists]
+ B -- Exists --> C[Return True]
+ B -- Does Not Exist --> D[Add Error Message]
+ D --> E[Return False]
+ C --> E
+ E --> F[End]
+```
+
+### `AfterParentChanged`
+
+```csharp
+public override void AfterParentChanged()
+```
+
+- **Description:** Validates the script after a parent change event.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[AfterParentChanged Method] --> B[Validate Script]
+ B --> C[End]
+```
+
+### `ToString`
+
+```csharp
+public override string ToString()
+```
+
+- **Description:** Returns a string representation of the `ExternalScript` instance.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[ToString Method] --> B[Format String]
+ B --> C[Return String]
+ C --> D[End]
+```
diff --git a/doc/task/utility/wait_altitude.md b/doc/task/utility/wait_altitude.md
new file mode 100644
index 00000000..bba5b94b
--- /dev/null
+++ b/doc/task/utility/wait_altitude.md
@@ -0,0 +1,166 @@
+# `WaitForAltitude` Class
+
+The `WaitForAltitude` class is part of the `NINA.Sequencer.SequenceItem.Utility` namespace and is used to wait until an astronomical object reaches a specified altitude.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Utility_WaitForAltitude_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Utility_WaitForAltitude_Description")]
+[ExportMetadata("Icon", "WaitForAltitudeSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Utility")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class WaitForAltitude : WaitForAltitudeBase, IValidatable
+```
+
+## Properties
+
+### `AboveOrBelow`
+
+- **Type:** `string`
+- **Description:** Defines whether the target altitude should be above (`>`) or below (`<`) a certain value.
+- **Json Property:** `[JsonProperty]`
+
+### `HasDsoParent`
+
+- **Type:** `bool`
+- **Description:** Indicates if this item has a Deep-Sky Object (DSO) parent.
+- **Json Property:** `[JsonProperty]`
+
+## Constructors
+
+### Default Constructor
+
+```csharp
+[ImportingConstructor]
+public WaitForAltitude(IProfileService profileService) : base(profileService, useCustomHorizon: false)
+```
+
+- **Parameters:**
+ - `profileService`: Service providing profile information.
+
+### Clone Constructor
+
+```csharp
+private WaitForAltitude(WaitForAltitude cloneMe) : this(cloneMe.ProfileService)
+```
+
+- **Parameters:**
+ - `cloneMe`: The instance to clone.
+
+## Methods
+
+### `Clone`
+
+```csharp
+public override object Clone()
+```
+
+- **Description:** Creates a deep copy of the current `WaitForAltitude` instance.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Clone Method] --> B[Create New WaitForAltitude]
+ B --> C[Copy Properties]
+ C --> D[Return New Instance]
+ D --> E[End]
+```
+
+### `Execute`
+
+```csharp
+public override async Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Continuously checks if the current altitude is above or below the target altitude and waits for the specified interval if not.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[Transform Coordinates to AltAz]
+ B --> C[Check If Altitude Meets Criteria]
+ C -- Yes --> D[Break Loop]
+ C -- No --> E[Delay for 1 Second]
+ E --> B
+ D --> F[End]
+```
+
+### `GetCurrentAltitude`
+
+```csharp
+public double GetCurrentAltitude(DateTime time, ObserverInfo observer)
+```
+
+- **Description:** Calculates the current altitude for a given time and observer.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[GetCurrentAltitude Method] --> B[Transform Coordinates to AltAz]
+ B --> C[Return Altitude]
+ C --> D[End]
+```
+
+### `CalculateExpectedTime`
+
+```csharp
+public override void CalculateExpectedTime()
+```
+
+- **Description:** Calculates the expected time for the object to reach the target altitude.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[CalculateExpectedTime Method] --> B[Get Current Altitude]
+ B --> C[Calculate Expected Time Common]
+ C --> D[End]
+```
+
+### `AfterParentChanged`
+
+```csharp
+public override void AfterParentChanged()
+```
+
+- **Description:** Updates coordinates based on the parent context and validates the data.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[AfterParentChanged Method] --> B[Retrieve Context Coordinates]
+ B --> C[Update Coordinates If Available]
+ C --> D[Set HasDsoParent]
+ D --> E[Validate Data]
+ E --> F[End]
+```
+
+### `Validate`
+
+```csharp
+public bool Validate()
+```
+
+- **Description:** Validates if the target altitude can be reached based on the current conditions.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Validate Method] --> B[Calculate Max Altitude]
+ B --> C[Calculate Min Altitude]
+ C --> D[Check Altitude Validity]
+ D -- Invalid --> E[Add Error Message]
+ D -- Valid --> F[Calculate Expected Time]
+ E --> G[Return False]
+ F --> H[Return True]
+ G --> H
+ H --> I[End]
+```
diff --git a/doc/task/utility/wait_altitude_base.md b/doc/task/utility/wait_altitude_base.md
new file mode 100644
index 00000000..75ce731b
--- /dev/null
+++ b/doc/task/utility/wait_altitude_base.md
@@ -0,0 +1,116 @@
+# WaitForAltitudeBase
+
+The `WaitForAltitudeBase` class is an abstract class used in the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application to handle operations related to waiting for a celestial body to reach a specified altitude. It includes properties and methods to manage altitude conditions and backward compatibility for deprecated fields.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+public abstract class WaitForAltitudeBase : SequenceItem
+```
+
+## Properties
+
+### `ProfileService`
+
+- **Type:** `IProfileService`
+- **Description:** Provides access to profile data used in altitude calculations and waiting processes.
+
+### `Data`
+
+- **Type:** `WaitLoopData`
+- **Description:** Contains configuration and data for the waiting loop, including altitude settings and comparison operators.
+
+### `Issues`
+
+- **Type:** `IList`
+- **Description:** A list of issues encountered during the waiting process.
+
+## Constructor
+
+```csharp
+public WaitForAltitudeBase(IProfileService profileService, bool useCustomHorizon)
+```
+
+- **Parameters:**
+ - `profileService`: Service for accessing profile data.
+ - `useCustomHorizon`: Boolean indicating whether to use custom horizon data.
+
+Initializes the `ProfileService` and `Data` properties.
+
+## Methods
+
+### `CalculateExpectedTime()`
+
+- **Description:** Abstract method that must be implemented by derived classes to calculate the expected time for the altitude condition to be met.
+
+## Obsolete Migration Properties
+
+These properties are retained for backward compatibility and are mapped to the `Data` property in the `WaitLoopData` class.
+
+### Deprecated Properties Flowchart
+
+```mermaid
+graph TD;
+ A[Deprecated Properties] --> B[Comparator]
+ A --> C[UserMoonAltitude]
+ A --> D[UserSunAltitude]
+ A --> E[AltitudeOffset]
+ A --> F[Altitude]
+ A --> G[Coordinates]
+
+ B --> H[DeprecatedComparator]
+ C --> I[DeprecatedUserMoonAltitude]
+ D --> J[DeprecatedUserSunAltitude]
+ E --> K[DeprecatedAltitudeOffset]
+ F --> L[DeprecatedAltitude]
+ G --> M[DeprecatedCoordinates]
+
+ H --> N[Data.Comparator]
+ I --> O[Data.Offset]
+ J --> P[Data.Offset]
+ K --> Q[Data.Offset]
+ L --> R[Data.Offset]
+ M --> S[Data.Coordinates]
+```
+
+### `Comparator`
+
+- **Deprecated Name:** `DeprecatedComparator`
+- **Type:** `ComparisonOperatorEnum`
+- **Description:** Specifies the comparison operator for altitude conditions. The value is converted to the current enum format.
+
+### `UserMoonAltitude`
+
+- **Deprecated Name:** `DeprecatedUserMoonAltitude`
+- **Type:** `double`
+- **Description:** Altitude offset for the moon.
+
+### `UserSunAltitude`
+
+- **Deprecated Name:** `DeprecatedUserSunAltitude`
+- **Type:** `double`
+- **Description:** Altitude offset for the sun.
+
+### `AltitudeOffset`
+
+- **Deprecated Name:** `DeprecatedAltitudeOffset`
+- **Type:** `double`
+- **Description:** General altitude offset.
+
+### `Altitude`
+
+- **Deprecated Name:** `DeprecatedAltitude`
+- **Type:** `double`
+- **Description:** Specific altitude value.
+
+### `Coordinates`
+
+- **Deprecated Name:** `DeprecatedCoordinates`
+- **Type:** `InputCoordinates`
+- **Description:** Coordinates used for the altitude calculation.
diff --git a/doc/task/utility/wait_horizon.md b/doc/task/utility/wait_horizon.md
new file mode 100644
index 00000000..f095f3c3
--- /dev/null
+++ b/doc/task/utility/wait_horizon.md
@@ -0,0 +1,167 @@
+# WaitUntilAboveHorizon
+
+The `WaitUntilAboveHorizon` class is part of the `NINA.Sequencer.SequenceItem.Utility` namespace and is used to wait until an astronomical object is above a specified horizon level.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+[ExportMetadata("Name", "Lbl_SequenceItem_Utility_WaitUntilAboveHorizon_Name")]
+[ExportMetadata("Description", "Lbl_SequenceItem_Utility_WaitUntilAboveHorizon_Description")]
+[ExportMetadata("Icon", "WaitForAltitudeSVG")]
+[ExportMetadata("Category", "Lbl_SequenceCategory_Utility")]
+[Export(typeof(ISequenceItem))]
+[JsonObject(MemberSerialization.OptIn)]
+public class WaitUntilAboveHorizon : WaitForAltitudeBase, IValidatable
+```
+
+## Properties
+
+### `HasDsoParent`
+
+- **Type:** `bool`
+- **Description:** Indicates if this item has a Deep-Sky Object (DSO) parent.
+- **Json Property:** `[JsonProperty]`
+
+### `UpdateInterval`
+
+- **Type:** `int`
+- **Description:** The interval, in seconds, for checking the altitude.
+- **Default Value:** `1`
+
+## Constructors
+
+### Default Constructor
+
+```csharp
+[ImportingConstructor]
+public WaitUntilAboveHorizon(IProfileService profileService) : base(profileService, useCustomHorizon: true)
+```
+
+- **Parameters:**
+ - `profileService`: Service providing profile information.
+
+### Clone Constructor
+
+```csharp
+private WaitUntilAboveHorizon(WaitUntilAboveHorizon cloneMe) : this(cloneMe.ProfileService)
+```
+
+- **Parameters:**
+ - `cloneMe`: The instance to clone.
+
+## Methods
+
+### `Clone`
+
+```csharp
+public override object Clone()
+```
+
+- **Description:** Creates a deep copy of the current `WaitUntilAboveHorizon` instance.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Clone Method] --> B[Create New WaitUntilAboveHorizon]
+ B --> C[Copy Properties]
+ C --> D[Return New Instance]
+ D --> E[End]
+```
+
+### `Execute`
+
+```csharp
+public override async Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Continuously checks if the current altitude is above the target altitude and waits for the specified interval if not.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[Set Target Altitude with Horizon]
+ B --> C[Transform Coordinates to AltAz]
+ C --> D[Check If Current Altitude > Target Altitude]
+ D -- Yes --> E[Log Completion]
+ D -- No --> F[Delay for Update Interval]
+ F --> B
+ E --> G[End]
+```
+
+### `GetCurrentAltitude`
+
+```csharp
+public double GetCurrentAltitude(DateTime time, ObserverInfo observer)
+```
+
+- **Description:** Calculates the current altitude for a given time and observer.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[GetCurrentAltitude Method] --> B[Transform Coordinates to AltAz]
+ B --> C[Return Altitude]
+ C --> D[End]
+```
+
+### `CalculateExpectedTime`
+
+```csharp
+public override void CalculateExpectedTime()
+```
+
+- **Description:** Calculates the expected time for the object to reach the target altitude.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[CalculateExpectedTime Method] --> B[Get Current Altitude]
+ B --> C[Calculate Expected Time Common]
+ C --> D[End]
+```
+
+### `AfterParentChanged`
+
+```csharp
+public override void AfterParentChanged()
+```
+
+- **Description:** Updates coordinates based on the parent context and validates the data.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[AfterParentChanged Method] --> B[Retrieve Context Coordinates]
+ B --> C[Update Coordinates If Available]
+ C --> D[Set HasDsoParent]
+ D --> E[Validate Data]
+ E --> F[End]
+```
+
+### `Validate`
+
+```csharp
+public bool Validate()
+```
+
+- **Description:** Validates if the target altitude can be reached based on the current horizon and coordinates.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Validate Method] --> B[Calculate Max Altitude]
+ B --> C[Calculate Minimum Horizon Altitude]
+ C --> D[Check If Max Altitude < Min Horizon Altitude]
+ D -- Yes --> E[Add Error Message]
+ D -- No --> F[Calculate Expected Time]
+ E --> G[Return False]
+ F --> H[Return True]
+ G --> H
+ H --> I[End]
+```
diff --git a/doc/task/utility/wait_loop.md b/doc/task/utility/wait_loop.md
new file mode 100644
index 00000000..47241fed
--- /dev/null
+++ b/doc/task/utility/wait_loop.md
@@ -0,0 +1,205 @@
+# WaitLoopData
+
+The `WaitLoopData` class is part of the `NINA.Sequencer.SequenceItem.Utility` namespace and is used to manage and calculate waiting times based on astronomical parameters such as altitude and horizon conditions.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+[JsonObject(MemberSerialization.OptIn)]
+public class WaitLoopData : BaseINPC
+```
+
+## Properties
+
+### `Coordinates`
+
+- **Type:** `InputCoordinates`
+- **Description:** Represents the input coordinates for the astronomical calculations.
+- **Json Property:** `[JsonProperty]`
+
+### `Offset`
+
+- **Type:** `double`
+- **Description:** The user input for the desired result. For horizons, it is `[current horizon] + offset => target horizon`. For altitudes, it is `[0] + offset => target altitude`.
+- **Json Property:** `[JsonProperty]`
+
+### `Comparator`
+
+- **Type:** `ComparisonOperatorEnum`
+- **Description:** The comparison operator used for determining if the conditions are met.
+- **Json Property:** `[JsonProperty]`
+
+### `UseCustomHorizon`
+
+- **Type:** `bool`
+- **Description:** Indicates if a custom horizon is used.
+
+### `Name`
+
+- **Type:** `string`
+- **Description:** The name associated with this `WaitLoopData` instance.
+
+### `Latitude`, `Longitude`, `Elevation`
+
+- **Type:** `double`
+- **Description:** The latitude, longitude, and elevation of the observer.
+
+### `Horizon`
+
+- **Type:** `CustomHorizon`
+- **Description:** Represents the custom horizon settings.
+
+### `Observer`
+
+- **Type:** `ObserverInfo`
+- **Description:** Information about the observer.
+
+### `TargetAltitude`
+
+- **Type:** `double`
+- **Description:** The target altitude to reach.
+
+### `RisingSettingDisplay`
+
+- **Type:** `string`
+- **Description:** Displays whether the object is rising or setting.
+
+### `IsRising`
+
+- **Type:** `bool`
+- **Description:** Indicates if the object is currently rising.
+
+### `CurrentAltitude`
+
+- **Type:** `double`
+- **Description:** The current altitude of the object.
+
+### `Approximate`
+
+- **Type:** `string`
+- **Description:** Indicates if the altitude is approximate.
+
+### `ExpectedDateTime`
+
+- **Type:** `DateTime`
+- **Description:** The expected date and time for reaching the target altitude.
+
+### `ExpectedTime`
+
+- **Type:** `string`
+- **Description:** The formatted string representing the expected time.
+
+## Constructors
+
+### Default Constructor
+
+```csharp
+public WaitLoopData(IProfileService profileService, bool useCustomHorizon, Action calculateExpectedTime, string name)
+```
+
+- **Parameters:**
+ - `profileService`: Service providing profile information.
+ - `useCustomHorizon`: Indicates if a custom horizon is used.
+ - `calculateExpectedTime`: Action to calculate expected time.
+ - `name`: The name associated with this instance.
+
+### Clone Constructor
+
+```csharp
+private WaitLoopData(WaitLoopData cloneMe) : this(cloneMe.profileService, cloneMe.UseCustomHorizon, cloneMe.calculateExpectedTime, cloneMe.Name)
+```
+
+- **Parameters:**
+ - `cloneMe`: The instance to clone.
+
+## Methods
+
+### `Clone`
+
+```csharp
+public WaitLoopData Clone()
+```
+
+- **Description:** Creates a deep copy of the current `WaitLoopData` instance.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Clone Method] --> B[Create New WaitLoopData]
+ B --> C[Copy Properties]
+ C --> D[Return New Instance]
+ D --> E[End]
+```
+
+### `SetCoordinates`
+
+```csharp
+public void SetCoordinates(InputCoordinates coordinates)
+```
+
+- **Description:** Sets new coordinates and resets the expected time.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[SetCoordinates Method] --> B[Check If Coordinates Changed]
+ B --> C[Update Coordinates]
+ C --> D[Reset Expected DateTime]
+ D --> E[End]
+```
+
+### `SetApproximate`
+
+```csharp
+public void SetApproximate(bool isApproximate)
+```
+
+- **Description:** Sets the approximate display value.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[SetApproximate Method] --> B[Check If Approximate]
+ B --> C[Update Approximate Property]
+ C --> D[End]
+```
+
+### `SetTargetAltitudeWithHorizon`
+
+```csharp
+public void SetTargetAltitudeWithHorizon(DateTime when)
+```
+
+- **Description:** Sets the target altitude based on the horizon for a specified date and time.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[SetTargetAltitudeWithHorizon Method] --> B[Calculate Target Altitude]
+ B --> C[Update Target Altitude]
+ C --> D[End]
+```
+
+### `GetTargetAltitudeWithHorizon`
+
+```csharp
+public double GetTargetAltitudeWithHorizon(DateTime when)
+```
+
+- **Description:** Calculates the target altitude based on the horizon for a specified date and time.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[GetTargetAltitudeWithHorizon Method] --> B[Transform Coordinates]
+ B --> C[Get Horizon Altitude]
+ C --> D[Calculate Target Altitude]
+ D --> E[Return Target Altitude]
+ E --> F[End]
+```
diff --git a/doc/task/utility/wait_moon.md b/doc/task/utility/wait_moon.md
new file mode 100644
index 00000000..83836873
--- /dev/null
+++ b/doc/task/utility/wait_moon.md
@@ -0,0 +1,118 @@
+# WaitForMoonAltitude
+
+The `WaitForMoonAltitude` class is a specific implementation of the `WaitForAltitudeBase` class used in the N.I.N.A. (Nighttime Imaging 'N' Astronomy) application. It manages waiting for the moon to reach a specified altitude based on the observer's location.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+public class WaitForMoonAltitude : WaitForAltitudeBase, IValidatable
+```
+
+## Properties
+
+### `ProfileService`
+
+- **Type:** `IProfileService`
+- **Description:** Provides access to profile data used for altitude calculations and waiting conditions.
+
+### `Data`
+
+- **Type:** `WaitLoopData`
+- **Description:** Holds configuration and data related to the waiting loop, including altitude settings and comparison operators.
+
+## Constructor
+
+```csharp
+[ImportingConstructor]
+public WaitForMoonAltitude(IProfileService profileService) : base(profileService, useCustomHorizon: false)
+```
+
+- **Parameters:**
+ - `profileService`: Service for accessing profile data.
+
+Initializes the `ProfileService` and `Data` properties. Sets the initial `Data.Offset` to `0d`.
+
+## Methods
+
+### `Execute`
+
+```csharp
+public override async Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Executes the waiting process until the moon reaches the target altitude. Reports progress and handles cancellation.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[CalculateExpectedTime]
+ B --> C[MustWait]
+ C -->|True| D[Report Progress]
+ D --> E[Delay]
+ E --> B
+ C -->|False| F[Exit Loop]
+ F --> G[End]
+```
+
+### `MustWait`
+
+```csharp
+private bool MustWait()
+```
+
+- **Description:** Determines if the process should continue waiting based on the current altitude and comparator.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[MustWait Method] --> B[CalculateExpectedTime]
+ B --> C[Check Comparator]
+ C -->|GREATER_THAN| D[CurrentAltitude > Offset]
+ C -->|Others| E[CurrentAltitude <= Offset]
+ D --> F[Return True]
+ E --> F
+ F --> G[End]
+```
+
+### `CalculateExpectedTime`
+
+```csharp
+public override void CalculateExpectedTime()
+```
+
+- **Description:** Calculates the expected time for the moon to reach the target altitude. Updates `Data` with current moon altitude and coordinates.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[CalculateExpectedTime Method] --> B[CalculateMoonRADec]
+ B --> C[GetMoonAltitude]
+ C --> D[CalculateExpectedTimeCommon]
+ D --> E[Update Data]
+ E --> F[End]
+```
+
+### `ToString`
+
+```csharp
+public override string ToString()
+```
+
+- **Description:** Returns a string representation of the current state, including category, item name, target altitude, comparator, and current altitude.
+
+## Validate Method
+
+```csharp
+public bool Validate()
+```
+
+- **Description:** Validates the current state of the instance. Calls `CalculateExpectedTime` and returns true.
diff --git a/doc/task/utility/wait_sun.md b/doc/task/utility/wait_sun.md
new file mode 100644
index 00000000..87bd8f44
--- /dev/null
+++ b/doc/task/utility/wait_sun.md
@@ -0,0 +1,117 @@
+# WaitForSunAltitude
+
+The `WaitForSunAltitude` class extends the `WaitForAltitudeBase` class and implements the `IValidatable` interface. It is used for waiting until the sun reaches a specified altitude, based on the observer's location.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+public class WaitForSunAltitude : WaitForAltitudeBase, IValidatable
+```
+
+## Properties
+
+### `ProfileService`
+
+- **Type:** `IProfileService`
+- **Description:** Provides access to profile data used for altitude calculations and waiting conditions.
+
+### `Data`
+
+- **Type:** `WaitLoopData`
+- **Description:** Holds configuration and data related to the waiting loop, including altitude settings and comparison operators.
+
+## Constructor
+
+```csharp
+[ImportingConstructor]
+public WaitForSunAltitude(IProfileService profileService) : base(profileService, useCustomHorizon: false)
+```
+
+- **Parameters:**
+ - `profileService`: Service for accessing profile data.
+
+Initializes the `ProfileService` and `Data` properties.
+
+## Methods
+
+### `Execute`
+
+```csharp
+public override async Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Executes the waiting process until the sun reaches the target altitude. Reports progress and handles cancellation.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[CalculateExpectedTime]
+ B --> C[MustWait]
+ C -->|True| D[Report Progress]
+ D --> E[Delay]
+ E --> B
+ C -->|False| F[Exit Loop]
+ F --> G[End]
+```
+
+### `MustWait`
+
+```csharp
+private bool MustWait()
+```
+
+- **Description:** Determines if the process should continue waiting based on the current sun altitude and comparator.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[MustWait Method] --> B[Check Comparator]
+ B -->|GREATER_THAN| C[CurrentAltitude > Offset]
+ B -->|Others| D[CurrentAltitude <= Offset]
+ C --> E[Return True]
+ D --> E
+ E --> F[End]
+```
+
+### `CalculateExpectedTime`
+
+```csharp
+public override void CalculateExpectedTime()
+```
+
+- **Description:** Calculates the expected time for the sun to reach the target altitude. Updates `Data` with current sun altitude and coordinates.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[CalculateExpectedTime Method] --> B[CalculateSunRADec]
+ B --> C[GetSunAltitude]
+ C --> D[CalculateExpectedTimeCommon]
+ D --> E[Update Data]
+ E --> F[End]
+```
+
+### `ToString`
+
+```csharp
+public override string ToString()
+```
+
+- **Description:** Returns a string representation of the current state, including category, item name, target altitude, comparator, and current sun altitude.
+
+## Validate Method
+
+```csharp
+public bool Validate()
+```
+
+- **Description:** Validates the current state of the instance. Calls `CalculateExpectedTime` and returns true.
diff --git a/doc/task/utility/wait_time.md b/doc/task/utility/wait_time.md
new file mode 100644
index 00000000..ece11b35
--- /dev/null
+++ b/doc/task/utility/wait_time.md
@@ -0,0 +1,197 @@
+# WaitForTime
+
+The `WaitForTime` class extends `SequenceItem` and implements the `IValidatable` interface. It is designed to wait until a specified time, considering optional time offsets and different date-time providers.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+public class WaitForTime : SequenceItem, IValidatable
+```
+
+## Properties
+
+### `DateTimeProviders`
+
+- **Type:** `IList`
+- **Description:** List of available date-time providers.
+
+### `SelectedProvider`
+
+- **Type:** `IDateTimeProvider`
+- **Description:** The currently selected date-time provider.
+
+### `Hours`
+
+- **Type:** `int`
+- **Description:** The target hour for the wait time.
+
+### `Minutes`
+
+- **Type:** `int`
+- **Description:** The target minute for the wait time.
+
+### `MinutesOffset`
+
+- **Type:** `int`
+- **Description:** Offset in minutes to adjust the target time.
+
+### `Seconds`
+
+- **Type:** `int`
+- **Description:** The target seconds for the wait time.
+
+### `Issues`
+
+- **Type:** `IList`
+- **Description:** List of validation issues.
+
+## Constructor
+
+### Default Constructor
+
+```csharp
+[ImportingConstructor]
+public WaitForTime(IList dateTimeProviders)
+```
+
+- **Parameters:**
+ - `dateTimeProviders`: List of available date-time providers.
+
+### Overloaded Constructor
+
+```csharp
+public WaitForTime(IList dateTimeProviders, IDateTimeProvider selectedProvider)
+```
+
+- **Parameters:**
+ - `dateTimeProviders`: List of available date-time providers.
+ - `selectedProvider`: The selected date-time provider.
+
+### Clone Constructor
+
+```csharp
+private WaitForTime(WaitForTime cloneMe) : this(cloneMe.DateTimeProviders, cloneMe.SelectedProvider)
+```
+
+- **Parameters:**
+ - `cloneMe`: The instance to clone.
+
+## Methods
+
+### `Clone`
+
+```csharp
+public override object Clone()
+```
+
+- **Description:** Creates a deep copy of the current `WaitForTime` instance.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Clone Method] --> B[Create New WaitForTime]
+ B --> C[Copy Properties]
+ C --> D[Return New Instance]
+ D --> E[End]
+```
+
+### `Validate`
+
+```csharp
+public bool Validate()
+```
+
+- **Description:** Validates the current state. Checks if time determination was successful and updates issues list.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Validate Method] --> B[Check Time Provider]
+ B --> C[Update Time if Fixed Provider]
+ C --> D[Check Time Determination]
+ D --> E[Add Validation Issues if Any]
+ E --> F[Return Validation Result]
+ F --> G[End]
+```
+
+### `UpdateTime`
+
+```csharp
+private void UpdateTime()
+```
+
+- **Description:** Updates the target time based on the selected provider and offset.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[UpdateTime Method] --> B[Get Reference Date]
+ B --> C[Check Fixed Time Provider]
+ C --> D[Calculate New Time]
+ D --> E[Set Hours, Minutes, Seconds]
+ E --> F[Update Success Status]
+ F --> G[End]
+```
+
+### `AfterParentChanged`
+
+```csharp
+public override void AfterParentChanged()
+```
+
+- **Description:** Updates the time when the parent changes.
+
+### `Execute`
+
+```csharp
+public override Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Executes the waiting task until the specified time is reached.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[Get Estimated Duration]
+ B --> C[Wait Until Duration Elapses]
+ C --> D[Report Progress]
+ D --> E[Handle Cancellation]
+ E --> F[End]
+```
+
+### `GetEstimatedDuration`
+
+```csharp
+public override TimeSpan GetEstimatedDuration()
+```
+
+- **Description:** Calculates the duration until the target time is reached, considering rollovers.
+
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[GetEstimatedDuration Method] --> B[Calculate Target Time]
+ B --> C[Adjust for Rollover]
+ C --> D[Calculate Time Difference]
+ D --> E[Return Duration]
+ E --> F[End]
+```
+
+### `ToString`
+
+```csharp
+public override string ToString()
+```
+
+- **Description:** Returns a string representation of the current state, including target time and offset.
diff --git a/doc/task/utility/wait_timespan.md b/doc/task/utility/wait_timespan.md
new file mode 100644
index 00000000..b6a99a9f
--- /dev/null
+++ b/doc/task/utility/wait_timespan.md
@@ -0,0 +1,112 @@
+# WaitForTimeSpan
+
+The `WaitForTimeSpan` class extends `SequenceItem` and is designed to wait for a specified time span. It provides a simple way to introduce delays in a sequence based on a duration defined in seconds.
+
+## Namespace
+
+```csharp
+namespace NINA.Sequencer.SequenceItem.Utility
+```
+
+## Class Declaration
+
+```csharp
+public class WaitForTimeSpan : SequenceItem
+```
+
+## Properties
+
+### `Time`
+
+- **Type:** `double`
+- **Description:** The duration to wait, in seconds.
+- **Json Property:** `[JsonProperty]`
+
+## Constructor
+
+### Default Constructor
+
+```csharp
+[ImportingConstructor]
+public WaitForTimeSpan()
+```
+
+- **Description:** Initializes a new instance with a default time of 1 second.
+
+### Clone Constructor
+
+```csharp
+private WaitForTimeSpan(WaitForTimeSpan cloneMe) : base(cloneMe)
+```
+
+- **Parameters:**
+ - `cloneMe`: The instance to clone.
+
+## Methods
+
+### `Clone`
+
+```csharp
+public override object Clone()
+```
+
+- **Description:** Creates a deep copy of the current `WaitForTimeSpan` instance.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Clone Method] --> B[Create New WaitForTimeSpan]
+ B --> C[Copy Properties]
+ C --> D[Return New Instance]
+ D --> E[End]
+```
+
+### `Execute`
+
+```csharp
+public override Task Execute(IProgress progress, CancellationToken token)
+```
+
+- **Description:** Executes the waiting task for the duration specified by `Time`.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[Execute Method] --> B[Get Estimated Duration]
+ B --> C[Wait Until Duration Elapses]
+ C --> D[Report Progress]
+ D --> E[Handle Cancellation]
+ E --> F[End]
+```
+
+### `GetEstimatedDuration`
+
+```csharp
+public override TimeSpan GetEstimatedDuration()
+```
+
+- **Description:** Returns the estimated duration to wait as a `TimeSpan`, based on the `Time` property.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[GetEstimatedDuration Method] --> B[Convert Time to TimeSpan]
+ B --> C[Return Duration]
+ C --> D[End]
+```
+
+### `ToString`
+
+```csharp
+public override string ToString()
+```
+
+- **Description:** Returns a string representation of the current state, including the time span to wait.
+- **Flowchart:**
+
+```mermaid
+graph TD;
+ A[ToString Method] --> B[Format String]
+ B --> C[Return String]
+ C --> D[End]
+```
diff --git a/doc/thirdparty.md b/doc/thirdparty.md
new file mode 100644
index 00000000..c2f1efc7
--- /dev/null
+++ b/doc/thirdparty.md
@@ -0,0 +1,70 @@
+# 需要使用到的第三方软件
+
+## 设备控制
+
+### ASCOM:Windows下的设备控制
+
+链接: [官网](https://www.ascom-standards.org/)
+
+由于ASCOM本体使用C#编写,因此不能直接通过C++控制,虽然可以模仿PHD2直接操作串口控制,但是这样的可用性很低。因此使用ASCOM Remote作为中转服务器。
+
+链接: [ASCOM Remote](https://github.com/ASCOMInitiative/ASCOMRemote)
+
+ASCOM Remote的通信基于http协议,消息格式为json,在服务器启动后会暴露指定的端口。
+
+可以模仿的实现:[Python下的ASCOM Remote客户端](https://github.com/ASCOMInitiative/alpyca)
+
+
+#### 使用流程
+
+用户启动ASCOMRemote服务器并选择需要使用的具体设备 -> 尝试扫描服务器,发现后建立连接 -> 根据API获取所有设备的信息 -> 连接完成
+
+参考文档:
+[ASCOM文档中心](https://www.ascom-standards.org/Documentation/Index.htm)
+[Alpaca指令定义](https://download.ascom-standards.org/docs/AlpacaIntroduction.pdf)
+[Alpyca文档](https://ascom-standards.org/alpyca/alpyca.pdf)
+[PHD2中的ASCOM客户端](https://github.com/OpenPHDGuiding/phd2/blob/master/cam_ascom.cpp)
+
+### INDI: Linux下的设备控制
+
+链接: [官网](https://github.com/indilib/)
+
+使用纯正C/C++编写,使用基于XML的tcp通信。__需要得到优先支持__
+
+[核心库](https://github.com/indilib/indi)
+[第三方驱动](https://github.com/indilib/indi-3rdparty)
+
+#### 使用流程
+
+有用户选择对应的驱动大类 -> 启动INDI服务器 -> (INDI服务器会自动扫描属于已经选择的驱动大类下的具体设备) -> 连接服务器 -> (第一次连接INDI会返回所有已有设备的信息,此时设备仍然未连接) -> 用户选择具体的设备型号 -> 发送连接指令 -> INDI服务器与具体设备连接 -> 连接流程结束
+
+
+#### 参考资料
+
+[Kstars中的INDI客户端](https://github.com/KDE/kstars/tree/master/kstars/indi)
+[PHD2中的INDI客户端](https://github.com/OpenPHDGuiding/phd2/blob/master/cam_indi.cpp)
+[Python下的INDI客户端](https://github.com/indilib/pyindi-client)
+
+## 导星
+
+### PHD2
+
+链接: [官网](https://github.com/OpenPHDGuiding/phd2)
+
+[服务器接口](https://github.com/OpenPHDGuiding/phd2/wiki/EventMonitoring)
+
+## 解析
+
+### Astrometry.net
+
+链接: [官网](https://github.com/dstndstn/astrometry.net)
+
+文档: [官方文档](https://astrometry.net/doc/readme.html)
+
+命令行工具
+
+### Astap
+
+[官网](https://www.hnsky.org/astap.htm)
+
+命令行工具
diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt
deleted file mode 100644
index 3bef5c55..00000000
--- a/driver/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# CMakeLists.txt for Atom-Driver
-# This project is licensed under the terms of the GPL3 license.
-#
-# Project Name: Atom-Driver
-# Description: A collection of drivers for Atom
-# Author: Max Qian
-# License: GPL3
-
-cmake_minimum_required(VERSION 3.20)
-project(atom-driver-interface C CXX)
-
-add_subdirectory(solver)
-add_subdirectory(client)
diff --git a/driver/camera/atom-asi/camera.cpp b/driver/camera/atom-asi/camera.cpp
deleted file mode 100644
index bef30bea..00000000
--- a/driver/camera/atom-asi/camera.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * camera.cpp
- *
- * Copyright (C) 2023-2024 Max Qian
- */
-
-/*************************************************
-
-Date: 2023-3-29
-
-Description: ASICamera Simulator and Basic Definition
-
-**************************************************/
-
-#include "camera.hpp"
-
-#include "atom/driver/macro.hpp"
-#include "atom/log/loguru.hpp"
-
-#include
-#include
-
-#define ASI_CAMERA_CONNECTION_CHECK \
- if (is_connected.load()) { \
- LOG_F(WARNING, "Camera already connected"); \
- return true; \
- }
-
-#define ASI_CAMERA_CONNECT_CHECK \
- if (!is_connected.load()) { \
- LOG_F(ERROR, "Camera not connected"); \
- return false; \
- }
-
-#define ASI_CAMERA_EXPOSURE_CHECK \
- if (is_exposing.load()) { \
- LOG_F(ERROR, "Camera is exposing"); \
- return false; \
- }
-
-#define ASI_CAMERA_VIDEO_CHECK \
- if (is_videoing.load()) { \
- LOG_F(ERROR, "Camera is videoing"); \
- return false; \
- }
-
-using ImgBufferPtr = std::unique_ptr;
-
-ASICamera::ASICamera(const std::string &name) : AtomCamera(name) {}
-
-ASICamera::~ASICamera() {}
-
-bool ASICamera::initialize() {
- AtomCamera::initialize();
-
- registerVariable("CAMERA_COUNT", 0, "the number of connected cameras");
- return true;
-}
-
-bool ASICamera::destroy() {
- AtomCamera::destroy();
- return true;
-}
-
-bool ASICamera::connect(const json ¶ms) {
- ASI_CAMERA_CONNECTION_CHECK;
- if (!params.contains("name")) {
- LOG_F(ERROR, "No camera name provided");
- return false;
- }
- auto camera_name = params["name"].get();
-
- auto camera_count = ASIGetNumOfConnectedCameras();
- if (camera_count <= 0) {
- LOG_F(ERROR,
- "ASI camera not found, please check the power supply or make "
- "sure the camera is connected.");
- return false;
- }
- for (int i = 0; i < camera_count; i++) {
- /*获取相机信息*/
- if ((errCode = ASIGetCameraProperty(&ASICameraInfo, i)) !=
- ASI_SUCCESS) {
- LOG_F(ERROR,
- "Unable to get {} configuration information,the error "
- "code is {},please check program permissions.\n",
- ASICameraInfo.Name, errCode);
- return false;
- }
- if (ASICameraInfo.Name == camera_name) {
- LOG_F(INFO, "Find camera {}", ASICameraInfo.Name);
- // Max: The member variable is faster than component variable
- setVariable("DEVICE_ID", ASICameraInfo.CameraID);
- setVariable("DEVICE_NAME", ASICameraInfo.Name);
- m_camera_id = ASICameraInfo.CameraID;
- m_camera_name = ASICameraInfo.Name;
- /*打开相机*/
- if ((errCode = ASIOpenCamera(ASICameraInfo.CameraID)) !=
- ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to turn on the {}, error code: {}.",
- ASICameraInfo.Name, errCode);
- return false;
- }
- /*初始化相机*/
- if ((errCode = ASIInitCamera(ASICameraInfo.CameraID)) !=
- ASI_SUCCESS) {
- LOG_F(ERROR,
- "Unable to initialize connection to "
- "camera,the error code is {}.",
- errCode);
- return false;
- }
- setVariable("DEVICE_CONNECTED", true);
- is_connected.store(true);
- LOG_F(INFO, "Camera connected successfully\n");
- return true;
- } else {
- LOG_F(ERROR, "This is not a designated camera");
- }
- }
- LOG_F(ERROR, "No camera found");
- return false;
-}
-
-bool ASICamera::disconnect(const json ¶ms) { /*在关闭相机之前停止所有任务*/
- ASI_CAMERA_CONNECT_CHECK;
- if (!params.empty()) {
- LOG_F(ERROR, "No parameters are allowed");
- return false;
- }
-
- if (is_videoing.load()) {
- if ((errCode = ASIStopVideoCapture(m_camera_id)) !=
- ASI_SUCCESS) // 停止视频拍摄
- {
- LOG_F(ERROR,
- "Unable to stop video capture,error code is {},please try "
- "again.",
- errCode);
- return false;
- }
- is_videoing.store(false);
- setVariable("CCD_VIDEO_STATUS", false);
- LOG_F(INFO, "Stop video capture");
- }
- if (is_exposing.load()) {
- if ((errCode = ASIStopExposure(m_camera_id)) !=
- ASI_SUCCESS) // 停止曝光
- {
- LOG_F(ERROR,
- "Unable to stop exposure,error code is {}, please try again.",
- errCode);
- return false;
- }
- is_exposing.store(false);
- setVariable("CCD_EXPOSURE_STATUS", false);
- LOG_F(INFO, "Stop exposure");
- }
- /*关闭相机*/
- if ((errCode = ASICloseCamera(m_camera_id)) != ASI_SUCCESS) // 关闭相机
- {
- LOG_F(ERROR, "Unable to turn off the camera,error code: {}", errCode);
- return false;
- }
- setVariable("DEVICE_CONNECTED", false);
- is_connected.store(false);
- LOG_F(INFO, "Disconnect from camera");
- return true;
-}
-
-bool ASICamera::reconnect(const json ¶ms) {
- ASI_CAMERA_CONNECT_CHECK;
- int timeout = 0;
- if (params.contains("timeout")) {
- timeout = params["timeout"].get();
- }
-
- if (!disconnect({})) {
- LOG_F(ERROR, "Unable to disconnect from camera");
- return false;
- }
- if (!connect({})) {
- LOG_F(ERROR, "Unable to connect to camera");
- return false;
- }
- LOG_F(INFO, "Reconnect to camera: {}",
- getVariable("DEVICE_NAME"));
- return true;
-}
-
-bool ASICamera::isConnected() { return is_connected.load(); }
-
-bool ASICamera::startExposure(const double &duration) {
- ASI_CAMERA_CONNECT_CHECK;
- if (is_exposing.load()) {
- LOG_F(ERROR, "Exposure is already in progress");
- return false;
- }
-
- const long blink_duration = duration * 1000000;
- LOG_F(INFO, "Blinking {} time(us) before exposure", blink_duration);
- if ((errCode = ASISetControlValue(m_camera_id, ASI_EXPOSURE, blink_duration,
- ASI_FALSE)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Failed to set blink exposure to {}us, error {}",
- blink_duration, errCode);
- return false;
- }
- if ((errCode = ASIStartExposure(m_camera_id, ASI_FALSE)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Failed to start blink exposure, error code: {}", errCode);
- return false;
- }
- is_exposing.store(true);
- setVariable("CCD_EXPOSURE_STATUS", true);
- // Max: A timer is needed here
- do {
- usleep(10000);
- errCode = ASIGetExpStatus(m_camera_id, &expStatus);
- } while (errCode == ASI_SUCCESS && expStatus == ASI_EXP_WORKING);
- if (errCode != ASI_SUCCESS) {
- LOG_F(ERROR, "Blink exposure failed, error {}, error code: {}", errCode,
- expStatus);
- return false;
- }
- is_exposing.store(false);
- setVariable("CCD_EXPOSURE_STATUS", false);
- LOG_F(INFO, "Blink exposure completed");
- return true;
-}
-
-bool ASICamera::abortExposure() {
- ASI_CAMERA_CONNECT_CHECK;
- if (!is_exposing.load()) {
- LOG_F(ERROR, "No exposure is in progress");
- return false;
- }
- if ((errCode = ASIStopExposure(m_camera_id)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to stop camera exposure, error code: {}", errCode);
- return false;
- }
- setVariable("CCD_EXPOSURE_STATUS", false);
- is_exposing.store(false);
- LOG_F(INFO, "Abort exposure");
- return true;
-}
-
-bool ASICamera::getExposureStatus() {
- ASI_CAMERA_CONNECT_CHECK;
- if ((errCode = ASIGetExpStatus(m_camera_id, &expStatus)) != ASI_SUCCESS) {
- LOG_F(INFO, "Camera is busy, status code: {}", errCode);
- setVariable("CCD_EXPOSURE_STATUS", true);
- is_exposing.store(true);
- return true;
- }
- LOG_F(INFO, "Camera is idle");
- return false;
-}
-
-bool ASICamera::getExposureResult() {
- ASI_CAMERA_CONNECT_CHECK;
- ASI_CAMERA_EXPOSURE_CHECK;
-
- GET_INT_VARIABLE(width);
- GET_INT_VARIABLE(height);
-
- long imgSize = width * height;
- //* (1 + (ASICAMERA->ImageType == ASI_IMG_RAW16));
-
- // 使用智能指针管理图像缓冲区内存
- ImgBufferPtr imgBuf(new unsigned char[imgSize]);
-
- /*曝光后获取图像信息*/
- int errCode = ASIGetDataAfterExp(m_camera_id, imgBuf.get(), imgSize);
- if (errCode != ASI_SUCCESS) {
- // 获取图像失败
- LOG_F(ERROR, "Unable to get image from camera, error code: {}",
- errCode);
- return;
- }
-
- // 图像下载完成
- LOG_F(INFO, "Download from camera completely.");
-
- GET_STR_VARIABLE(upload_mode);
- if (upload_mode == "LOCAL") [[likely]] {
- // Max: image filename generation logic is needed
- std::string FitsName = "test.fits";
- LOG_F(INFO, "Upload mode is LOCAL, save image to {}", FitsName);
- /*将图像写入本地文件*/
- // auto res = getComponent("LITHIUM_IMAGE")
- // ->runFunc("SaveImage", {{"filename", FitsName},
- // {"data", imgBuf},
- //{ "size", imgSize }
- //});
- // if (res.contains("error")) {
- // LOG_F(ERROR, "Unable to save image to {}, error: {}", FitsName,
- // res["error"].get());
- // return false;
- //}
- } else if (upload_mode == "CLIENT") [[unlikely]] {
- } else if (upload_mode == "None") [[unlikely]] {
- LOG_F(INFO, "Upload mode is NONE, skip upload");
- } else {
- LOG_F(ERROR, "Invalid upload mode: {}", upload_mode);
- return false;
- }
- return true;
-}
-
-bool ASICamera::saveExposureResult() { return true; }
-
-bool ASICamera::startVideo() { return true; }
-
-bool ASICamera::stopVideo() { return true; }
-
-bool ASICamera::getVideoStatus() { return true; }
-
-bool ASICamera::getVideoResult() { return true; }
-
-bool ASICamera::saveVideoResult() { return true; }
-
-bool ASICamera::startCooling() { return true; }
-
-bool ASICamera::stopCooling() { return true; }
-
-bool ASICamera::getCoolingStatus() { return true; }
-
-bool ASICamera::isCoolingAvailable() { return true; }
-
-bool ASICamera::getTemperature() { return true; }
-
-bool ASICamera::getCoolingPower() { return true; }
-
-bool ASICamera::setTemperature(const double &temperature) {
- ASI_CAMERA_CONNECT_CHECK;
- ASI_CAMERA_EXPOSURE_CHECK;
- ASI_CAMERA_VIDEO_CHECK;
- if (!is_cooling_available) {
- LOG_F(ERROR, "Cooling is not available");
- return false;
- }
- /*转化温度参数*/
- long TargetTemp;
- if (temperature > 0.5)
- TargetTemp = static_cast(temperature + 0.49);
- else if (temperature < 0.5)
- TargetTemp = static_cast(temperature - 0.49);
- else
- TargetTemp = 0;
- /*设置相机温度*/
- if ((errCode = ASISetControlValue(m_camera_id, ASI_TEMPERATURE, TargetTemp,
- ASI_FALSE)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to set camera temperature, error code: {}",
- errCode);
- return false;
- }
- setVariable("CCD_TEMPERATURE_VALUE", TargetTemp);
- LOG_F(INFO, "Set camera cooling temperature to {}", TargetTemp);
- return true;
-}
-
-bool ASICamera::setCoolingPower(const double &power) { return true; }
-
-bool ASICamera::getGain() {
- ASI_CAMERA_CONNECT_CHECK;
- long gain;
- if ((errCode = ASIGetControlValue(m_camera_id, ASI_GAIN, &gain, NULL)) !=
- ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to get camera gain, error code: {}", errCode);
- return false;
- }
- setVariable("CCD_GAIN", static_cast(gain));
- m_gain.store(static_cast(gain));
- LOG_F(INFO, "Get camera gain: {}", gain);
- return true;
-}
-
-bool ASICamera::setGain(const int &gain) {
- ASI_CAMERA_CONNECT_CHECK;
- ASI_CAMERA_EXPOSURE_CHECK;
- ASI_CAMERA_VIDEO_CHECK;
- if ((errCode = ASISetControlValue(m_camera_id, ASI_GAIN, gain,
- ASI_FALSE)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to set camera gain,error code: {}", errCode);
- return false;
- }
- setVariable("CCD_GAIN", gain);
- m_gain.store(gain);
- LOG_F(INFO, "Set camera gain to {}", gain);
- return true;
-}
-
-bool ASICamera::isGainAvailable() {
- LOG_F(INFO, "Gain is available for {}", m_camera_name);
- return true;
-}
-
-bool ASICamera::getOffset() {
- ASI_CAMERA_CONNECT_CHECK;
- long offset;
- if ((errCode = ASIGetControlValue(m_camera_id, ASI_BRIGHTNESS, &offset,
- NULL)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to get camera offset, error code: {}", errCode);
- return false;
- }
- setVariable("CCD_OFFSET", static_cast(offset));
- m_offset.store(static_cast(offset));
- LOG_F(INFO, "Get camera offset: {}", offset);
- return true;
-}
-
-bool ASICamera::setOffset(const int &offset) {
- ASI_CAMERA_CONNECT_CHECK;
- ASI_CAMERA_EXPOSURE_CHECK;
- ASI_CAMERA_VIDEO_CHECK;
- if ((errCode = ASISetControlValue(m_camera_id, ASI_BRIGHTNESS, offset,
- ASI_FALSE)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to set camera offset, error code: {}", errCode);
- return false;
- }
- setVariable("CCD_OFFSET", offset);
- m_offset.store(offset);
- LOG_F(INFO, "Set camera offset to {}", offset);
- return true;
-}
-
-bool ASICamera::isOffsetAvailable() {
- LOG_F(INFO, "Offset is available for {}", m_camera_name);
- return true;
-}
-
-bool ASICamera::getISO() {
- LOG_F(ERROR, "ISO is not available for {}", m_camera_name);
- return false;
-}
-
-bool ASICamera::setISO(const int &iso) {
- LOG_F(ERROR, "ISO is not available for {}", m_camera_name);
- return false;
-}
-
-bool ASICamera::isISOAvailable() {
- LOG_F(INFO, "ISO is not available for {}", m_camera_name);
- return false;
-}
-
-bool ASICamera::getFrame() { return true; }
-
-bool ASICamera::setFrame(const int &x, const int &y, const int &w,
- const int &h) {
- return true;
-}
-
-bool ASICamera::isFrameSettingAvailable() { return true; }
-
-bool ASICamera::getBinning() { return true; }
-
-bool ASICamera::setBinning(const int &hor, const int &ver) { return true; }
-
-bool ASICamera::getFrameType() { return true; }
-
-bool ASICamera::setFrameType(FrameType type) { return true; }
-
-bool ASICamera::getUploadMode() { return true; }
-
-bool ASICamera::setUploadMode(UploadMode mode) { return true; }
-
-bool ASICamera::refreshCameraInfo() {
- if ((errCode = ASIGetCameraProperty(&ASICameraInfo, i)) != ASI_SUCCESS) {
- LOG_F(ERROR, "Unable to get camera information, error code: {}",
- errCode);
- return false;
- }
- return true;
-}
diff --git a/driver/camera/atom-asi/camera.hpp b/driver/camera/atom-asi/camera.hpp
deleted file mode 100644
index ad3db211..00000000
--- a/driver/camera/atom-asi/camera.hpp
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef ATOM_ASI_COMPONENT_HPP
-#define ATOM_ASI_COMPONENT_HPP
-
-#include "atom/driver/camera.hpp"
-
-#include "driverlibs/libasi/ASICamera2.h"
-
-#include
-
-class ASICamera : public AtomCamera {
-public:
- explicit ASICamera(const std::string &name);
- ~ASICamera();
-
- bool initialize() final;
- bool destroy() final;
-
- bool connect(const json ¶ms) final;
-
- bool disconnect(const json ¶ms) final;
-
- bool reconnect(const json ¶ms) final;
-
- bool isConnected() final;
-
- bool startExposure(const double &duration) final;
-
- bool abortExposure() final;
-
- bool getExposureStatus() final;
-
- bool getExposureResult() final;
-
- bool saveExposureResult() final;
-
- bool startVideo() final;
-
- bool stopVideo() final;
-
- bool getVideoStatus() final;
-
- bool getVideoResult() final;
-
- bool saveVideoResult() final;
-
- bool startCooling() final;
-
- bool stopCooling() final;
-
- bool getCoolingStatus() final;
-
- bool isCoolingAvailable() final;
-
- bool getTemperature() final;
-
- bool getCoolingPower() final;
-
- bool setTemperature(const double &temperature) final;
-
- bool setCoolingPower(const double &power) final;
-
- bool getGain() final;
-
- bool setGain(const int &gain) final;
-
- bool isGainAvailable() final;
-
- bool getOffset() final;
-
- bool setOffset(const int &offset) final;
-
- bool isOffsetAvailable() final;
-
- bool getISO() final;
-
- bool setISO(const int &iso) final;
-
- bool isISOAvailable() final;
-
- bool getFrame() final;
-
- bool setFrame(const int &x, const int &y, const int &w, const int &h) final;
-
- bool isFrameSettingAvailable() final;
-
- bool getBinning() final;
-
- bool setBinning(const int &hor, const int &ver) final;
-
- bool getFrameType() final;
-
- bool setFrameType(FrameType type) final;
-
- bool getUploadMode() final;
-
- bool setUploadMode(UploadMode mode) final;
-
-private:
- bool refreshCameraInfo();
-
- /*ASI相机参数*/
- ASI_CAMERA_INFO ASICameraInfo;
- ASI_ERROR_CODE errCode;
- ASI_EXPOSURE_STATUS expStatus;
-
- int m_camera_id;
- std::string m_camera_name;
-
- std::atomic_bool is_connected;
- std::atomic_bool is_exposing;
- std::atomic_bool is_videoing;
- std::atomic_bool is_cooling;
-
- bool is_cooling_available;
-
- std::atomic m_gain;
- std::atomic m_offset;
-};
-
-#endif
diff --git a/driver/camera/atom-asi/package.json b/driver/camera/atom-asi/package.json
deleted file mode 100644
index 70ecb92d..00000000
--- a/driver/camera/atom-asi/package.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "name": "Atom-Camera-ASI",
- "version": "1.0.0",
- "type": "shared",
- "description": "Atom driver for ASI Camera",
- "license": "LGPL-3.0-or-later",
- "author": "Max Qian",
- "repository": {
- "type": "git",
- "url": "https://github.com/ElementAstro/Atom-ASI"
- },
- "bugs": {
- "url": "https://github.com/ElementAstro/Atom-ASI/issues"
- },
- "homepage": "https://github.com/ElementAstro/Atom-ASI",
- "keywords": [
- "asi",
- "camera",
- "filter wheel"
- ],
- "scripts": {
- "dev": "./atom-asi --standalone",
- "build": "cmake --build-type=Release -- -j 4",
- "lint": "clang-format -i src/*.cpp src/*.h"
- },
- "dependencies": {
- "asi-sdk" : "^1.34"
- },
- "main": {
- "ASICamera": {
- "func": "getInstance",
- "type" : "shared"
- }
- }
-}
diff --git a/driver/camera/atom-touptek/camera.cpp b/driver/camera/atom-touptek/camera.cpp
deleted file mode 100644
index f0afffd1..00000000
--- a/driver/camera/atom-touptek/camera.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * camera.cpp
- *
- * Copyright (C) 2023-2024 Max Qian
- */
-
-/*************************************************
-
-Date: 2023-3-29
-
-Description: Touptek Camera
-
-**************************************************/
-
-#include "camera.hpp"
-
-#include "atom/log/loguru.hpp"
-
-#include
-
-ToupCamera::ToupCamera(const std::string &name)
- : ToupCamera(name) {}
-
-ToupCamera::~ToupCamera() {}
-
-bool ToupCamera::initialize() { return true; }
-
-bool ToupCamera::destroy() { return true; }
-
-bool ToupCamera::connect(const json ¶ms) { return true; }
-
-bool ToupCamera::disconnect(const json ¶ms) { return true; }
-
-bool ToupCamera::reconnect(const json ¶ms) { return true; }
-
-bool ToupCamera::isConnected() { return true; }
-
-bool ToupCamera::startExposure(const double &duration) { return true; }
-
-bool ToupCamera::abortExposure() { return true; }
-
-bool ToupCamera::getExposureStatus() { return true; }
-
-bool ToupCamera::getExposureResult() { return true; }
-
-bool ToupCamera::saveExposureResult() { return true; }
-
-bool ToupCamera::startVideo() { return true; }
-
-bool ToupCamera::stopVideo() { return true; }
-
-bool ToupCamera::getVideoStatus() { return true; }
-
-bool ToupCamera::getVideoResult() { return true; }
-
-bool ToupCamera::saveVideoResult() { return true; }
-
-bool ToupCamera::startCooling() { return true; }
-
-bool ToupCamera::stopCooling() { return true; }
-
-bool ToupCamera::getCoolingStatus() { return true; }
-
-bool ToupCamera::isCoolingAvailable() { return true; }
-
-bool ToupCamera::getTemperature() { return true; }
-
-bool ToupCamera::getCoolingPower() { return true; }
-
-bool ToupCamera::setTemperature(const double &temperature) { return true; }
-
-bool ToupCamera::setCoolingPower(const double &power) { return true; }
-
-bool ToupCamera::getGain() { return true; }
-
-bool ToupCamera::setGain(const int &gain) { return true; }
-
-bool ToupCamera::isGainAvailable() { return true; }
-
-bool ToupCamera::getOffset() { return true; }
-
-bool ToupCamera::setOffset(const int &offset) { return true; }
-
-bool ToupCamera::isOffsetAvailable() { return true; }
-
-bool ToupCamera::getISO() { return true; }
-
-bool ToupCamera::setISO(const int &iso) { return true; }
-
-bool ToupCamera::isISOAvailable() { return true; }
-
-bool ToupCamera::getFrame() { return true; }
-
-bool ToupCamera::setFrame(const int &x, const int &y, const int &w,
- const int &h) {
- return true;
-}
-
-bool ToupCamera::isFrameSettingAvailable() { return true; }
-
-bool ToupCamera::getBinning() { return true; }
-
-bool ToupCamera::setBinning(const int &hor, const int &ver) { return true; }
-
-bool ToupCamera::getFrameType() { return true; }
-
-bool ToupCamera::setFrameType(FrameType type) { return true; }
-
-bool ToupCamera::getUploadMode() { return true; }
-
-bool ToupCamera::setUploadMode(UploadMode mode) { return true; }
diff --git a/driver/camera/atom-touptek/camera.hpp b/driver/camera/atom-touptek/camera.hpp
deleted file mode 100644
index 77ddd772..00000000
--- a/driver/camera/atom-touptek/camera.hpp
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef ATOM_TOUPTEK_COMPONENT_HPP
-#define ATOM_TOUPTEK_COMPONENT_HPP
-
-#include "atom/driver/camera.hpp"
-
-#include "libtouptek/toupcam.h"
-
-#include
-
-class ToupCamera : public AtomCamera {
-public:
- explicit ToupCamera(const std::string &name);
- ~ToupCamera();
-
- bool initialize() final;
- bool destroy() final;
-
- bool connect(const json ¶ms) final;
-
- bool disconnect(const json ¶ms) final;
-
- bool reconnect(const json ¶ms) final;
-
- bool isConnected() final;
-
- bool startExposure(const double &duration) final;
-
- bool abortExposure() final;
-
- bool getExposureStatus() final;
-
- bool getExposureResult() final;
-
- bool saveExposureResult() final;
-
- bool startVideo() final;
-
- bool stopVideo() final;
-
- bool getVideoStatus() final;
-
- bool getVideoResult() final;
-
- bool saveVideoResult() final;
-
- bool startCooling() final;
-
- bool stopCooling() final;
-
- bool getCoolingStatus() final;
-
- bool isCoolingAvailable() final;
-
- bool getTemperature() final;
-
- bool getCoolingPower() final;
-
- bool setTemperature(const double &temperature) final;
-
- bool setCoolingPower(const double &power) final;
-
- bool getGain() final;
-
- bool setGain(const int &gain) final;
-
- bool isGainAvailable() final;
-
- bool getOffset() final;
-
- bool setOffset(const int &offset) final;
-
- bool isOffsetAvailable() final;
-
- bool getISO() final;
-
- bool setISO(const int &iso) final;
-
- bool isISOAvailable() final;
-
- bool getFrame() final;
-
- bool setFrame(const int &x, const int &y, const int &w, const int &h) final;
-
- bool isFrameSettingAvailable() final;
-
- bool getBinning() final;
-
- bool setBinning(const int &hor, const int &ver) final;
-
- bool getFrameType() final;
-
- bool setFrameType(FrameType type) final;
-
- bool getUploadMode() final;
-
- bool setUploadMode(UploadMode mode) final;
-
-private:
-};
-
-#endif
diff --git a/driver/camera/atom-touptek/detail/libtoupbase.cpp b/driver/camera/atom-touptek/detail/libtoupbase.cpp
deleted file mode 100644
index 52c6e077..00000000
--- a/driver/camera/atom-touptek/detail/libtoupbase.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * libtoupbase.cpp
- *
- * Copyright (C) 2023-2024 Max Qian
- */
-
-/*************************************************
-
-Date: 20234-3-1
-
-Description: ToupBase Library
-
-**************************************************/
-
-#include "libtoupbase.hpp"
-#include
-
-std::string errorCodes(HRESULT rc) {
- static std::unordered_map errCodes = {
- {0x00000000, "Success"},
- {0x00000001, "Yet another success"},
- {0x8000ffff, "Catastrophic failure"},
- {0x80004001, "Not supported or not implemented"},
- {0x80070005, "Permission denied"},
- {0x8007000e, "Out of memory"},
- {0x80070057, "One or more arguments are not valid"},
- {0x80004003, "Pointer that is not valid"},
- {0x80004005, "Generic failure"},
- {0x8001010e, "Call function in the wrong thread"},
- {0x8007001f, "Device not functioning"},
- {0x800700aa, "The requested resource is in use"},
- {0x8000000a,
- "The data necessary to complete this operation is not yet available"},
- {0x8001011f,
- "This operation returned because the timeout period expired"}};
-
- const std::unordered_map::iterator it =
- errCodes.find(rc);
- if (it != errCodes.end())
- return it->second;
- else {
- char str[256];
- snprintf(str, sizeof(str), "Unknown error: 0x%08x", rc);
- return std::string(str);
- }
-}
diff --git a/driver/camera/atom-touptek/detail/libtoupbase.hpp b/driver/camera/atom-touptek/detail/libtoupbase.hpp
deleted file mode 100644
index ad4e4923..00000000
--- a/driver/camera/atom-touptek/detail/libtoupbase.hpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * libtoupbase.cpp
- *
- * Copyright (C) 2023-2024 Max Qian
- */
-
-/*************************************************
-
-Date: 20234-3-1
-
-Description: ToupBase Library
-
-**************************************************/
-
-#pragma once
-
-#include
-
-#ifdef BUILD_TOUPCAM
-#include
-#define FP(x) Toupcam_##x
-#define CP(x) TOUPCAM_##x
-#define XP(x) Toupcam##x
-#define THAND HToupcam
-#define DNAME "ToupTek"
-#elif BUILD_ALTAIRCAM
-#include
-#define FP(x) Altaircam_##x
-#define CP(x) ALTAIRCAM_##x
-#define XP(x) Altaircam##x
-#define THAND HAltaircam
-#define DNAME "Altair"
-#elif BUILD_BRESSERCAM
-#include
-#define FP(x) Bressercam_##x
-#define CP(x) BRESSERCAM_##x
-#define XP(x) Bressercam##x
-#define THAND HBressercam
-#define DNAME "Bresser"
-#elif BUILD_MALLINCAM
-#include
-#define FP(x) Mallincam_##x
-#define CP(x) MALLINCAM_##x
-#define XP(x) Mallincam##x
-#define THAND HMallincam
-#define DNAME "MALLINCAM"
-#elif BUILD_NNCAM
-#include
-#define FP(x) Nncam_##x
-#define CP(x) NNCAM_##x
-#define XP(x) Nncam##x
-#define THAND HNncam
-#define DNAME "Nn"
-#elif BUILD_OGMACAM
-#include
-#define FP(x) Ogmacam_##x
-#define CP(x) OGMACAM_##x
-#define XP(x) Ogmacam##x
-#define THAND HOgmacam
-#define DNAME "OGMAVision"
-#elif BUILD_OMEGONPROCAM
-#include
-#define FP(x) Omegonprocam_##x
-#define CP(x) OMEGONPROCAM_##x
-#define XP(x) Omegonprocam##x
-#define THAND HOmegonprocam
-#define DNAME "Astroshop"
-#elif BUILD_STARSHOOTG
-#include
-#define FP(x) Starshootg_##x
-#define CP(x) STARSHOOTG_##x
-#define XP(x) Starshootg##x
-#define THAND HStarshootg
-#define DNAME "Orion"
-#elif BUILD_TSCAM
-#include
-#define FP(x) Tscam_##x
-#define CP(x) TSCAM_##x
-#define XP(x) Tscam##x
-#define THAND HTscam
-#define DNAME "Teleskop"
-#elif BUILD_MEADECAM
-#include
-#define FP(x) Toupcam_##x
-#define CP(x) TOUPCAM_##x
-#define XP(x) Toupcam##x
-#define THAND HToupcam
-#define DNAME "Meade"
-#endif
-
-extern std::string errorCodes(HRESULT rc);
diff --git a/driver/camera/atom-touptek/package.json b/driver/camera/atom-touptek/package.json
deleted file mode 100644
index f9ebf862..00000000
--- a/driver/camera/atom-touptek/package.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "name": "Atom-Camera-Touptek",
- "version": "1.0.0",
- "type": "shared",
- "description": "Atom driver for Touptek Camera",
- "license": "LGPL-3.0-or-later",
- "author": "Max Qian",
- "repository": {
- "type": "git",
- "url": "https://github.com/ElementAstro/Atom-Touptek"
- },
- "bugs": {
- "url": "https://github.com/ElementAstro/Atom-Touptek/issues"
- },
- "homepage": "https://github.com/ElementAstro/Atom-Touptek",
- "keywords": [
- "asi",
- "camera",
- "filter wheel"
- ],
- "scripts": {
- "dev": "./atom-touptek --standalone",
- "build": "cmake --build-type=Release -- -j 4",
- "lint": "clang-format -i src/*.cpp src/*.h"
- },
- "dependencies": {
- "asi-sdk" : "^1.34"
- },
- "main": {
- "TouptekCamera": {
- "func": "getInstance",
- "type" : "shared"
- }
- }
-}
diff --git a/driver/client/CMakeLists.txt b/driver/client/CMakeLists.txt
deleted file mode 100644
index f331bc44..00000000
--- a/driver/client/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# CMakeLists.txt for Atom-Client
-# This project is licensed under the terms of the GPL3 license.
-#
-# Project Name: Atom-Client
-# Description: A collection of clients for Atom. For cross-platform use.
-# Author: Max Qian
-# License: GPL3
-
-cmake_minimum_required(VERSION 3.20)
-project(atom-client C CXX)
-
-# add_subdirectory(atom-hydrogen)
diff --git a/driver/client/README.md b/driver/client/README.md
deleted file mode 100644
index 73c291d1..00000000
--- a/driver/client/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Atom Driver - Client
-
-Here are all of the official drivers which serve as bridges to overcome the differences between platform:
-
-+ Windows : ASCOM(com/direct) or Alpaca(remote/http) via ASCOMRemote
-+ Linux: INDI(remote/tcp) or Hydrogen(remote/tcp)
-+ All platform: INDIGo(remote/tcp)
-
-## Content
-
-+ atom-ascom
-+ atom-alpaca
-+ atom-hydrogen
-+ atom-indigo
diff --git a/driver/client/atom-alpaca/CMakeLists.txt b/driver/client/atom-alpaca/CMakeLists.txt
deleted file mode 100644
index 56d36c9b..00000000
--- a/driver/client/atom-alpaca/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-add_library(
- ascom_remote SHARED
- ascom_camera.cpp
- ascom_camera.hpp
-
- ascom_covercalibrator.cpp
- ascom_covercalibrator.hpp
-
- ascom_device.cpp
- ascom_device.hpp
-
- ascom_filterwheel.cpp
- ascom_filterwheel.hpp
-
- ascom_focuser.cpp
- ascom_focuser.hpp
-
- ascom_telescope.cpp
- ascom_telescope.hpp
-)
-
-target_link_libraries(ascom_remote PRIVATE LithiumDriver LithiumProperty loguru cpp_httplib)
-
-target_link_libraries(ascom_remote PRIVATE ${OPENSSL_LIBRARIES})
-
-if(WIN32)
-target_link_libraries(ascom_remote PRIVATE wsock32 ws2_32)
-endif()
-
-include_directories(${CMAKE_SOURCE_DIR}/atom/lidrvier)
diff --git a/driver/client/atom-alpaca/camera.hpp b/driver/client/atom-alpaca/camera.hpp
deleted file mode 100644
index c43893a3..00000000
--- a/driver/client/atom-alpaca/camera.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#include
-
-enum ImageArrayElementTypes { INT, FLOAT }; // 假设ImageArrayElementTypes是一个枚举类型
-
-class ImageMetadata {
-private:
- int metavers;
- ImageArrayElementTypes imgtype;
- ImageArrayElementTypes xmtype;
- int rank;
- int x_size;
- int y_size;
- int z_size;
-
-public:
- explicit ImageMetadata(
- int metadata_version,
- ImageArrayElementTypes image_element_type,
- ImageArrayElementTypes transmission_element_type,
- int rank,
- int num_x,
- int num_y,
- int num_z
- ) :
- metavers(metadata_version),
- imgtype(image_element_type),
- xmtype(transmission_element_type),
- rank(rank),
- x_size(num_x),
- y_size(num_y),
- z_size(num_z)
- {}
-
- int get_MetadataVersion() {
- return metavers;
- }
-
- ImageArrayElementTypes get_ImageElementType() {
- return imgtype;
- }
-
- ImageArrayElementTypes get_TransmissionElementType() {
- return xmtype;
- }
-
- int get_Rank() {
- return rank;
- }
-
- int get_Dimension1() {
- return x_size;
- }
-
- int get_Dimension2() {
- return y_size;
- }
-
- int get_Dimension3() {
- return z_size;
- }
-};
-
-int main() {
- ImageMetadata metadata(1, INT, FLOAT, 2, 640, 480, 0);
- std::cout << "Metadata version: " << metadata.get_MetadataVersion() << std::endl;
- std::cout << "Image element type: " << metadata.get_ImageElementType() << std::endl;
- std::cout << "Transmission element type: " << metadata.get_TransmissionElementType() << std::endl;
- std::cout << "Rank: " << metadata.get_Rank() << std::endl;
- std::cout << "Dimension 1: " << metadata.get_Dimension1() << std::endl;
- std::cout << "Dimension 2: " << metadata.get_Dimension2() << std::endl;
- std::cout << "Dimension 3: " << metadata.get_Dimension3() << std::endl;
-
- return 0;
-}
diff --git a/driver/client/atom-alpaca/device.cpp b/driver/client/atom-alpaca/device.cpp
deleted file mode 100644
index 6c9894b1..00000000
--- a/driver/client/atom-alpaca/device.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * device.cpp
- *
- * Copyright (C) 2023-2024 Max Qian
- */
-
-/*************************************************
-
-Date: 20234-3-1
-
-Description: Basic Device Definition of Alpaca
-
-**************************************************/
-
-#include "device.hpp"
-
-#include
-#include
-#include
-
-
-#include "httplib.h"
-
-constexpr int API_VERSION = 1;
-
-Device::Device(const std::string &address, const std::string &device_type,
- int device_number, const std::string &protocol)
- : address(address),
- device_type(device_type),
- device_number(device_number),
- protocol(protocol) {
- api_version = API_VERSION;
- base_url = protocol + "://" + address + "/api/v" +
- std::to_string(api_version) + "/" + device_type + "/" +
- std::to_string(device_number);
-}
-
-std::string Device::Action(const std::string &ActionName,
- const std::vector &Parameters) {
- return _put("action", {{"Action", ActionName}, {"Parameters", Parameters}})
- .at("Value");
-}
-
-void Device::CommandBlind(const std::string &Command, bool Raw) {
- _put("commandblind", {{"Command", Command}, {"Raw", Raw}});
-}
-
-bool Device::CommandBool(const std::string &Command, bool Raw) {
- return _put("commandbool", {{"Command", Command}, {"Raw", Raw}})
- .at("Value");
-}
-
-std::string Device::CommandString(const std::string &Command, bool Raw) {
- return _put("commandstring", {{"Command", Command}, {"Raw", Raw}})
- .at("Value");
-}
-
-bool Device::get_Connected() const { return _get("connected") == "true"; }
-
-void Device::set_Connected(bool ConnectedState) {
- _put("connected", {{"Connected", ConnectedState}});
-}
-
-std::string Device::get_Description() const { return _get("description"); }
-
-std::vector Device::get_DriverInfo() const {
- std::vector driver_info;
- std::string driver_info_str = _get("driverinfo");
- size_t start_pos = 0;
- size_t end_pos = driver_info_str.find(',');
- while (end_pos != std::string::npos) {
- driver_info.push_back(
- driver_info_str.substr(start_pos, end_pos - start_pos));
- start_pos = end_pos + 1;
- end_pos = driver_info_str.find(',', start_pos);
- }
- driver_info.push_back(driver_info_str.substr(start_pos));
- return driver_info;
-}
-
-std::string Device::get_DriverVersion() const { return _get("driverversion"); }
-
-int Device::get_InterfaceVersion() const {
- return std::stoi(_get("interfaceversion"));
-}
-
-std::string Device::get_Name() const { return _get("name"); }
-
-std::vector Device::get_SupportedActions() const {
- std::string supported_actions_str = _get("supportedactions");
- std::vector supported_actions;
- size_t start_pos = 0;
- size_t end_pos = supported_actions_str.find(',');
- while (end_pos != std::string::npos) {
- supported_actions.push_back(
- supported_actions_str.substr(start_pos, end_pos - start_pos));
- start_pos = end_pos + 1;
- end_pos = supported_actions_str.find(',', start_pos);
- }
- supported_actions.push_back(supported_actions_str.substr(start_pos));
- return supported_actions;
-}
-
-json Device::_get(const std::string &attribute,
- const std::map &data = {},
- double tmo = 5.0) const {
- httplib::Client client(address.c_str());
- std::string path = base_url + "/" + attribute;
-
- std::lock_guard lock(_ctid_lock);
- std::string client_trans_id = std::to_string(_client_trans_id++);
- std::string client_id = std::to_string(_client_id);
-
- client.set_timeout(tmo);
-
- httplib::Headers headers = {{"ClientTransactionID", client_trans_id},
- {"ClientID", client_id}};
-
- httplib::Result response = client.Get(path.c_str(), headers, data);
-
- if (response && response->status == 200) {
- json j = json::parse(response->body);
- int error_number = j["ErrorNumber"];
- std::string error_message = j["ErrorMessage"];
- if (error_number != 0) {
- if (error_number == 0x0400)
- throw NotImplementedException(error_message);
- else if (error_number == 0x0401)
- throw InvalidValueException(error_message);
- else if (error_number == 0x0402)
- throw ValueNotSetException(error_message);
- else if (error_number == 0x0407)
- throw NotConnectedException(error_message);
- else if (error_number == 0x0408)
- throw ParkedException(error_message);
- else if (error_number == 0x0409)
- throw SlavedException(error_message);
- else if (error_number == 0x040B)
- throw InvalidOperationException(error_message);
- else if (error_number == 0x040C)
- throw ActionNotImplementedException(error_message);
- else if (error_number >= 0x500 && error_number <= 0xFFF)
- throw DriverException(error_number, error_message);
- else
- throw DriverException(error_number, error_message);
- }
- return j;
- } else {
- throw AlpacaRequestException(
- response ? response->status : -1,
- response ? response->body : "Request failed");
- }
-}
-
-json Device::_put(const std::string &attribute,
- const std::map &data = {},
- double tmo = 5.0) const {
- httplib::Client client(address.c_str());
- std::string path = base_url + "/" + attribute;
-
- std::lock_guard lock(_ctid_lock);
- std::string client_trans_id = std::to_string(_client_trans_id++);
- std::string client_id = std::to_string(_client_id);
-
- client.set_timeout(tmo);
-
- httplib::Headers headers = {{"ClientTransactionID", client_trans_id},
- {"ClientID", client_id}};
-
- json json_data = data;
- std::string body = json_data.dump();
-
- httplib::Result response =
- client.Put(path.c_str(), headers, body, "application/json");
-
- if (response && response->status == 200) {
- json j = json::parse(response->body);
- int error_number = j["ErrorNumber"];
- std::string error_message = j["ErrorMessage"];
- if (error_number != 0) {
- if (error_number == 0x0400)
- throw NotImplementedException(error_message);
- else if (error_number == 0x0401)
- throw InvalidValueException(error_message);
- else if (error_number == 0x0402)
- throw ValueNotSetException(error_message);
- else if (error_number == 0x0407)
- throw NotConnectedException(error_message);
- else if (error_number == 0x0408)
- throw ParkedException(error_message);
- else if (error_number == 0x0409)
- throw SlavedException(error_message);
- else if (error_number == 0x040B)
- throw InvalidOperationException(error_message);
- else if (error_number == 0x040C)
- throw ActionNotImplementedException(error_message);
- else if (error_number >= 0x500 && error_number <= 0xFFF)
- throw DriverException(error_number, error_message);
- else
- throw DriverException(error_number, error_message);
- }
- return j;
- } else {
- throw AlpacaRequestException(
- response ? response->status : -1,
- response ? response->body : "Request failed");
- }
-}
-
-int Device::_client_id = std::random_device()();
-int Device::_client_trans_id = 1;
-std::mutex Device::_ctid_lock;
diff --git a/driver/client/atom-alpaca/device.hpp b/driver/client/atom-alpaca/device.hpp
deleted file mode 100644
index 6389a009..00000000
--- a/driver/client/atom-alpaca/device.hpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * device.hpp
- *
- * Copyright (C) 2023-2024 Max Qian
- */
-
-/*************************************************
-
-Date: 20234-3-1
-
-Description: Basic Device Definition of Alpaca
-
-**************************************************/
-
-#ifndef ATOM_ALPACA_DEVICE_HPP
-#define ATOM_ALPACA_DEVICE_HPP
-
-#include
-#include