openapi: 3.1.0 info: title: Home Automation Backend (Python) description: Home automation backend with auth, runtime config, Home Assistant integrations, TickTick integration, and SQLite-backed recorders. version: 0.1.0 paths: /status: get: tags: - system summary: Get Status operationId: get_status_status_get responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/StatusResponse' /login: get: tags: - auth summary: Login Page operationId: login_page_login_get responses: '200': description: Successful Response content: text/html: schema: type: string post: tags: - auth summary: Login Submit operationId: login_submit_login_post requestBody: content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/Body_login_submit_login_post' required: true responses: '200': description: Successful Response content: text/html: schema: type: string '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /config/change-password: post: tags: - auth summary: Change Password Submit operationId: change_password_submit_config_change_password_post requestBody: content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/Body_change_password_submit_config_change_password_post' required: true responses: '200': description: Successful Response content: text/html: schema: type: string '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /logout: post: tags: - auth summary: Logout operationId: logout_logout_post requestBody: content: application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/Body_logout_logout_post' required: true responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /: get: tags: - pages summary: Home operationId: home__get responses: '200': description: Successful Response content: text/html: schema: type: string /admin: get: tags: - pages summary: Admin Redirect operationId: admin_redirect_admin_get responses: '200': description: Successful Response content: text/html: schema: type: string /config: get: tags: - pages summary: Config Page operationId: config_page_config_get responses: '200': description: Successful Response content: text/html: schema: type: string post: tags: - pages summary: Config Submit operationId: config_submit_config_post responses: '200': description: Successful Response content: text/html: schema: type: string /config/smtp/test: post: tags: - pages summary: Smtp Test Submit operationId: smtp_test_submit_config_smtp_test_post responses: '200': description: Successful Response content: text/html: schema: type: string /api/config: get: tags: - api-config summary: Get Config description: Return all configuration sections. Secret field values are masked (empty string). operationId: get_config_api_config_get responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ConfigResponse' put: tags: - api-config summary: Put Config description: 'Save configuration updates. - Blank secret value keeps the existing stored value (no change). - Invalid values return 422 and nothing is written to the database.' operationId: put_config_api_config_put parameters: - name: X-CSRF-Token in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Csrf-Token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ConfigUpdateRequest' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ConfigUpdateResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/locations: get: tags: - api-data summary: Get Locations description: 'Return location records with optional time-window filtering and pagination. - ``start`` / ``end`` are ISO8601 strings; filtering is **inclusive** on both bounds. - Results are ordered by ``datetime`` ascending. - ``limit`` is capped at 5000 to prevent full-table exports.' operationId: get_locations_api_locations_get parameters: - name: limit in: query required: false schema: type: integer maximum: 5000 minimum: 1 default: 1000 title: Limit - name: offset in: query required: false schema: type: integer minimum: 0 default: 0 title: Offset - name: start in: query required: false schema: anyOf: - type: string - type: 'null' title: Start - name: end in: query required: false schema: anyOf: - type: string - type: 'null' title: End responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/LocationsResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/poo: get: tags: - api-data summary: Get Poo description: 'Return poo records ordered by timestamp descending (most recent first). ``limit`` is capped at 1000 to prevent full-table exports.' operationId: get_poo_api_poo_get parameters: - name: limit in: query required: false schema: type: integer maximum: 1000 minimum: 1 default: 100 title: Limit - name: offset in: query required: false schema: type: integer minimum: 0 default: 0 title: Offset responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/PooResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/public-ip: get: tags: - api-data summary: Get Public Ip description: 'Return the current public IP state and recent history. - ``state`` is ``null`` if no IP check has been performed yet. - ``history`` is ordered by ``observed_at`` descending (most recent first). - ``limit`` applies to the history list and is capped at 1000.' operationId: get_public_ip_api_public_ip_get parameters: - name: limit in: query required: false schema: type: integer maximum: 1000 minimum: 1 default: 100 title: Limit responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/PublicIPResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/session: get: tags: - api-session summary: Get Session description: Return the current session user and CSRF token. Returns 401 if not authenticated. operationId: get_session_api_session_get responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/SessionResponse' /api/auth/login: post: tags: - api-session summary: Post Login description: 'Authenticate with username and password. On success, sets an HttpOnly session cookie and returns the session user + CSRF token. On failure, returns 401 with no cookie set. No X-CSRF-Token required (unauthenticated endpoint).' operationId: post_login_api_auth_login_post requestBody: content: application/json: schema: $ref: '#/components/schemas/LoginRequest' required: true responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/SessionResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/auth/logout: post: tags: - api-session summary: Post Logout description: 'Revoke the current session and clear the session cookie. Requires authentication and X-CSRF-Token header. Returns 204 No Content.' operationId: post_logout_api_auth_logout_post parameters: - name: X-CSRF-Token in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Csrf-Token responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/auth/password: post: tags: - api-session summary: Post Change Password description: 'Change the current user''s password. Requires authentication and X-CSRF-Token header. On AuthPasswordChangeError returns 400 with a generic message. On success, force_password_change becomes False (handled by the service). Returns 204 No Content.' operationId: post_change_password_api_auth_password_post parameters: - name: X-CSRF-Token in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Csrf-Token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PasswordChangeRequest' responses: '200': description: Successful Response content: application/json: schema: {} '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /homeassistant/publish: post: tags: - homeassistant summary: Publish From Homeassistant operationId: publish_from_homeassistant_homeassistant_publish_post responses: '200': description: Successful Response content: application/json: schema: {} /location/record: post: tags: - location summary: Create Location Record operationId: create_location_record_location_record_post responses: '200': description: Successful Response content: application/json: schema: {} /poo/record: post: tags: - poo summary: Create Poo Record operationId: create_poo_record_poo_record_post responses: '200': description: Successful Response content: application/json: schema: {} /poo/latest: get: tags: - poo summary: Notify Latest Poo operationId: notify_latest_poo_poo_latest_get responses: '200': description: Successful Response content: application/json: schema: {} /public-ip/check: get: tags: - public-ip summary: Run Public Ip Check operationId: run_public_ip_check_public_ip_check_get responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/PublicIPCheckResponse' /ticktick/auth/start: get: tags: - ticktick summary: Start Ticktick Auth operationId: start_ticktick_auth_ticktick_auth_start_get responses: '200': description: Successful Response content: application/json: schema: {} /ticktick/auth/code: get: tags: - ticktick summary: Handle Ticktick Auth Code operationId: handle_ticktick_auth_code_ticktick_auth_code_get responses: '200': description: Successful Response content: application/json: schema: {} components: schemas: Body_change_password_submit_config_change_password_post: properties: current_password: type: string title: Current Password new_password: type: string title: New Password confirm_password: type: string title: Confirm Password csrf_token: type: string title: Csrf Token type: object required: - current_password - new_password - confirm_password - csrf_token title: Body_change_password_submit_config_change_password_post Body_login_submit_login_post: properties: username: type: string title: Username password: type: string title: Password csrf_token: type: string title: Csrf Token type: object required: - username - password - csrf_token title: Body_login_submit_login_post Body_logout_logout_post: properties: csrf_token: type: string title: Csrf Token type: object required: - csrf_token title: Body_logout_logout_post ConfigField: properties: env_name: type: string title: Env Name label: type: string title: Label value: type: string title: Value secret: type: boolean title: Secret input_type: type: string title: Input Type configured: type: boolean title: Configured type: object required: - env_name - label - value - secret - input_type - configured title: ConfigField ConfigResponse: properties: sections: items: $ref: '#/components/schemas/ConfigSection' type: array title: Sections type: object required: - sections title: ConfigResponse ConfigSection: properties: name: type: string title: Name fields: items: $ref: '#/components/schemas/ConfigField' type: array title: Fields type: object required: - name - fields title: ConfigSection ConfigUpdateRequest: properties: updates: additionalProperties: type: string type: object title: Updates type: object required: - updates title: ConfigUpdateRequest description: Flat mapping of env_name → value, mirroring the existing form semantics. ConfigUpdateResponse: properties: sections: items: $ref: '#/components/schemas/ConfigSection' type: array title: Sections type: object required: - sections title: ConfigUpdateResponse HTTPValidationError: properties: detail: items: $ref: '#/components/schemas/ValidationError' type: array title: Detail type: object title: HTTPValidationError LocationRecord: properties: person: type: string title: Person datetime: type: string title: Datetime latitude: type: number title: Latitude longitude: type: number title: Longitude altitude: anyOf: - type: number - type: 'null' title: Altitude type: object required: - person - datetime - latitude - longitude - altitude title: LocationRecord LocationsResponse: properties: items: items: $ref: '#/components/schemas/LocationRecord' type: array title: Items limit: type: integer title: Limit offset: type: integer title: Offset type: object required: - items - limit - offset title: LocationsResponse LoginRequest: properties: username: type: string title: Username password: type: string title: Password type: object required: - username - password title: LoginRequest PasswordChangeRequest: properties: current_password: type: string title: Current Password new_password: type: string title: New Password confirm_password: type: string title: Confirm Password type: object required: - current_password - new_password - confirm_password title: PasswordChangeRequest PooRecord: properties: timestamp: type: string title: Timestamp status: type: string title: Status latitude: type: number title: Latitude longitude: type: number title: Longitude type: object required: - timestamp - status - latitude - longitude title: PooRecord PooResponse: properties: items: items: $ref: '#/components/schemas/PooRecord' type: array title: Items limit: type: integer title: Limit offset: type: integer title: Offset type: object required: - items - limit - offset title: PooResponse PublicIPCheckResponse: properties: status: type: string enum: - first_seen - unchanged - changed - error title: Status checked_at: type: string format: date-time title: Checked At changed: type: boolean title: Changed type: object required: - status - checked_at - changed title: PublicIPCheckResponse PublicIPHistorySchema: properties: id: type: integer title: Id ipv4: type: string title: Ipv4 observed_at: type: string format: date-time title: Observed At change_type: type: string title: Change Type provider: anyOf: - type: string - type: 'null' title: Provider type: object required: - id - ipv4 - observed_at - change_type - provider title: PublicIPHistorySchema PublicIPResponse: properties: state: anyOf: - $ref: '#/components/schemas/PublicIPStateSchema' - type: 'null' history: items: $ref: '#/components/schemas/PublicIPHistorySchema' type: array title: History type: object required: - state - history title: PublicIPResponse PublicIPStateSchema: properties: id: type: integer title: Id current_ipv4: type: string title: Current Ipv4 previous_ipv4: anyOf: - type: string - type: 'null' title: Previous Ipv4 first_seen_at: type: string format: date-time title: First Seen At last_checked_at: type: string format: date-time title: Last Checked At last_changed_at: anyOf: - type: string format: date-time - type: 'null' title: Last Changed At last_check_status: type: string title: Last Check Status last_check_error: anyOf: - type: string - type: 'null' title: Last Check Error last_provider: anyOf: - type: string - type: 'null' title: Last Provider type: object required: - id - current_ipv4 - previous_ipv4 - first_seen_at - last_checked_at - last_changed_at - last_check_status - last_check_error - last_provider title: PublicIPStateSchema SessionResponse: properties: user: $ref: '#/components/schemas/SessionUser' csrf_token: type: string title: Csrf Token type: object required: - user - csrf_token title: SessionResponse SessionUser: properties: username: type: string title: Username force_password_change: type: boolean title: Force Password Change type: object required: - username - force_password_change title: SessionUser StatusResponse: properties: status: type: string title: Status type: object required: - status title: StatusResponse ValidationError: properties: loc: items: anyOf: - type: string - type: integer type: array title: Location msg: type: string title: Message type: type: string title: Error Type type: object required: - loc - msg - type title: ValidationError