openapi: 3.1.0
info:
  title: Cozify Han API
  version: '1.0'
  termsOfService: https://en.cozify.fi/pages/privacy-policy
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  description: This is the [OpenAPI specification](./han-1.0.yaml) for the Cozify HAN reader.
  contact:
    email: support@cozify.fi
servers:
  - url: /
    description: Relative to the current HAN reader origin
security:
  - {}
tags:
  - name: System
    description: System status, events, and connectivity
  - name: Configuration
    description: HAN reader configuration and setup
  - name: Network
    description: Network operations and WiFi management
  - name: Meter
    description: Electricity meter data reported by the HAN reader
paths:
  /han:
    get:
      operationId: Info
      summary: Info
      description: |
        Returns general information about the HAN reader, including UUID, name, model, serial, firmware version, state, MAC address, network IPs, online status, and release channel.
      tags:
        - System
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HanStateMessage'
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
  /ws:
    get:
      operationId: WebSocket
      summary: WebSocket
      description: |
        Establishes a WebSocket connection to the HAN reader.
        This endpoint upgrades the HTTP connection to a WebSocket (ws:// or wss://).
        The WebSocket protocol is used for real-time, bidirectional communication.
        Current payload behavior:
        - Sends an initial state payload with discriminator `type = HAN_STATE_MESSAGE`.
        - Streams electricity meter payloads with discriminator `type = HAN_METER_MESSAGE`.
      tags:
        - System
      responses:
        '101':
          description: Switching Protocols (WebSocket handshake successful)
        '200':
          description: Successful operation
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
  /sse:
    get:
      operationId: ServerSentEvents
      summary: ServerSentEvents
      description: |
        Opens a stream of server-sent events (SSE) from the HAN reader.
        The response uses the `text/event-stream` content type.
        Current event names and payload discriminator values:
        - `HAN_METER_MESSAGE`: streams electricity meter payloads.
        - `HAN_STATE_MESSAGE`: initial state snapshot sent when the client connects.
      tags:
        - System
      responses:
        '200':
          description: Successful operation
          content:
            text/event-stream:
              schema:
                type: string
                description: Stream of events in SSE format
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
  /set-up:
    post:
      operationId: Setup
      summary: Setup
      description: |
        Sets up the HAN reader with basic WiFi configuration. Accepts a JSON object with WiFi enablement, SSID, and password. Returns success status and message. May trigger a HAN reader reboot.
      tags:
        - Configuration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                s:
                  type: boolean
                  description: Enable WiFi (must be true)
                ss:
                  type: string
                  description: WiFi SSID
                sp:
                  type: string
                  description: WiFi password
              required:
                - s
                - ss
                - sp
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    description: Whether the setup was successful
                  message:
                    type: string
                    description: Status or error message
                required:
                  - success
                  - message
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
  /configuration:
    get:
      operationId: Configuration
      summary: Configuration
      description: |
        Returns the current HAN reader configuration, including firmware version, timezone, spot price usage, fixed price, pricing and fuse settings, ethernet, and WiFi settings.

        - Pricing and fuse settings include the main fuse value used by the HAN reader.
        - Ethernet and WiFi settings include enablement, network mode (dhcp/static), and network details.
        - Passwords and secrets are masked as "***" if configured.
      tags:
        - Configuration
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    description: Response type identifier
                    enum:
                      - HAN_CONFIGURATION
                  v:
                    type: string
                    description: Firmware version
                  t:
                    type: string
                    description: Timezone (e.g., Europe/Helsinki)
                  s:
                    type: boolean
                    description: Use spot price
                  p:
                    type: number
                    description: Fixed price
                  m:
                    type: object
                    description: Pricing and fuse settings used by the HAN reader
                    properties:
                      f:
                        type: integer
                        description: Main fuse value
                    required:
                      - f
                  e:
                    type: object
                    description: Ethernet settings
                    properties:
                      e:
                        type: boolean
                        description: Ethernet enabled
                      'n':
                        type: object
                        description: Ethernet network settings
                        properties:
                          m:
                            $ref: '#/components/schemas/NetworkMode'
                          i:
                            type: string
                            description: IP address
                          s:
                            type: string
                            description: Netmask
                          g:
                            type: string
                            description: Gateway
                          d1:
                            type: string
                            description: DNS 1
                          d2:
                            type: string
                            description: DNS 2
                        required:
                          - m
                  w:
                    type: object
                    description: WiFi settings
                    properties:
                      e:
                        type: boolean
                        description: WiFi enabled
                      s:
                        type: string
                        description: WiFi SSID (empty if not set)
                      p:
                        type: string
                        description: WiFi password (masked as "***" if configured, empty otherwise)
                      w:
                        type: integer
                        description: WiFi power (in dBm)
                      z:
                        type: boolean
                        description: WiFi power save enabled
                      b:
                        type: boolean
                        description: WiFi 11b enabled
                      'n':
                        type: object
                        description: WiFi network settings
                        properties:
                          m:
                            $ref: '#/components/schemas/NetworkMode'
                          i:
                            type: string
                            description: IP address
                          s:
                            type: string
                            description: Netmask
                          g:
                            type: string
                            description: Gateway
                          d1:
                            type: string
                            description: DNS 1
                          d2:
                            type: string
                            description: DNS 2
                        required:
                          - m
                    required:
                      - e
                      - s
                      - p
                      - w
                      - z
                      - b
                      - 'n'
                required:
                  - type
                  - v
                  - t
                  - s
                  - p
                  - m
                  - e
                  - w
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
    post:
      operationId: ConfigurationUpdate
      summary: ConfigurationUpdate
      description: |
        Updates the HAN reader configuration. Accepts a JSON object with any subset of the configuration fields as defined in the GET response. Returns success status and message. Some changes may require a HAN reader reboot.
      tags:
        - Configuration
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                s:
                  type: boolean
                  description: Use spot price
                p:
                  type: number
                  description: Fixed price
                m:
                  type: object
                  description: Pricing and fuse settings used by the HAN reader
                  properties:
                    f:
                      type: integer
                      description: Main fuse value
                e:
                  type: object
                  description: Ethernet settings
                  properties:
                    e:
                      type: boolean
                      description: Ethernet enabled
                    'n':
                      type: object
                      description: Ethernet network settings
                      properties:
                        m:
                          type: string
                          description: Network mode (dhcp/static)
                          enum:
                            - dhcp
                            - static
                        i:
                          type: string
                          description: IP address
                        s:
                          type: string
                          description: Netmask
                        g:
                          type: string
                          description: Gateway
                        d1:
                          type: string
                          description: DNS 1
                        d2:
                          type: string
                          description: DNS 2
                w:
                  type: object
                  description: WiFi settings
                  properties:
                    e:
                      type: boolean
                      description: WiFi enabled
                    s:
                      type: string
                      description: WiFi SSID
                    p:
                      type: string
                      description: WiFi password ("***" to keep unchanged)
                    w:
                      type: integer
                      description: WiFi power (in dBm)
                    z:
                      type: boolean
                      description: WiFi power save enabled
                    b:
                      type: boolean
                      description: WiFi 11b enabled
                    'n':
                      type: object
                      description: WiFi network settings
                      properties:
                        m:
                          type: string
                          description: Network mode (dhcp/static)
                          enum:
                            - dhcp
                            - static
                        i:
                          type: string
                          description: IP address
                        s:
                          type: string
                          description: Netmask
                        g:
                          type: string
                          description: Gateway
                        d1:
                          type: string
                          description: DNS 1
                        d2:
                          type: string
                          description: DNS 2
      responses:
        '200':
          description: Configuration update result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    description: Whether the update was successful
                  message:
                    type: string
                    description: Status or error message
                required:
                  - success
                  - message
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
  /meter:
    get:
      operationId: Meter
      summary: Meter
      description: Returns the latest electricity meter data received by the HAN reader. This endpoint is intended for the latest live reading values reported by the electricity meter.
      tags:
        - Meter
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HanMeterMessage'
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader has not received any data from the electricity meter yet.
  /meter/id:
    get:
      operationId: MeterIdentity
      summary: Meter identity
      description: Returns low-churn electricity meter identity fields parsed from HAN telegrams. This endpoint is intended for metadata that changes rarely, so clients can fetch meter identity separately from high-frequency /meter polling.
      tags:
        - Meter
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HanMeterIdentityMessage'
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader has not received any data from the electricity meter yet.
  /health:
    get:
      operationId: Health
      summary: Health
      description: |
        Returns health and status information about the HAN reader, including UUID, hostname, heap memory statistics, CPU reset reason, and uptime.
      tags:
        - System
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HanHealthMessage'
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
  /scan-networks:
    get:
      operationId: ScanNetworks
      summary: ScanNetworks
      description: |
        Initiates or returns the result of a WiFi network scan. If a scan is running or requested, returns status. If scan is complete, returns a list of found networks with details.

        **Note:** Performing a WiFi scan may temporarily disconnect the HAN reader from its currently connected WiFi network.

        - If the scan is running or just started, returns `{ "status": "SCAN_RUNNING" }`.
        - If the scan failed, returns `{ "status": "SCAN_FAILED" }`.
        - If the scan succeeded, returns `{ "status": "SCAN_SUCCESS", "networks": [...] }`.

        Each network entry includes SSID, BSSID, RSSI, channel, and authentication type.
      tags:
        - Network
      parameters:
        - in: header
          name: X-Scan-Start
          schema:
            type: string
          required: false
          description: If present, triggers a new WiFi scan.
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    $ref: '#/components/schemas/ScanStatus'
                  networks:
                    type: array
                    description: List of found WiFi networks (present only if status is SCAN_SUCCESS)
                    items:
                      type: object
                      properties:
                        ssid:
                          type: string
                          description: WiFi network SSID
                        bssid:
                          type: string
                          description: WiFi network BSSID (MAC address)
                        rssi:
                          type: integer
                          description: Signal strength (RSSI)
                        channel:
                          type: integer
                          description: WiFi channel
                        auth:
                          $ref: '#/components/schemas/WifiAuthType'
                      required:
                        - ssid
                        - bssid
                        - rssi
                        - channel
                        - auth
                required:
                  - status
        '400':
          x-summary: Bad request
          description: Received parameters are not valid.
        '401':
          x-summary: Unauthorized
          description: Invalid access token.
        '403':
          x-summary: Forbidden
          description: Access token does not have permission to access this resource.
        '503':
          x-summary: Service unavailable
          description: HAN reader is unable to process request.
components:
  schemas:
    HanStateMessage:
      type: object
      description: Current HAN reader state message.
      additionalProperties: false
      properties:
        type:
          type: string
          description: Message discriminator. Always HAN_STATE_MESSAGE.
          enum:
            - HAN_STATE_MESSAGE
          example: HAN_STATE_MESSAGE
        uuid:
          type: string
          description: Unique stable identifier of the HAN reader.
          example: 7f2f8c1e-2c6d-4a25-b2b1-6f6a27d5f5de
        name:
          type: string
          description: HAN reader hostname used on the local network.
          example: Cozify-HAN-123-456
        model:
          type: string
          description: Hardware model identifier.
          example: HAN
        serial:
          type: string
          description: HAN reader serial number.
          example: HAN12345678
        version:
          type: string
          description: Installed firmware version.
          example: 1.0.1.0
        state:
          type: string
          description: Internal lifecycle state of the HAN reader.
          example: REGISTERED
        mac:
          type: string
          description: HAN reader MAC address.
          example: AA:BB:CC:DD:EE:FF
        ethIp:
          type: string
          description: Ethernet IPv4 address, or 0.0.0.0 when not assigned.
          example: 192.168.1.50
        wifiIp:
          type: string
          description: Wi-Fi IPv4 address, or 0.0.0.0 when not assigned.
          example: 192.168.2.50
        online:
          type: boolean
          description: True when the HAN reader is considered online and operational.
          example: true
        channel:
          type: string
          description: Firmware channel identifier.
          example: release
      required:
        - type
        - uuid
        - name
        - model
        - serial
        - version
        - state
        - mac
        - ethIp
        - wifiIp
        - online
        - channel
    NetworkMode:
      type: string
      enum:
        - dhcp
        - static
    HanMeterMessage:
      type: object
      description: Electricity meter data message received by the HAN reader.
      additionalProperties: false
      properties:
        type:
          type: string
          description: Identifier of the message type. Always HAN_METER_MESSAGE.
          enum:
            - HAN_METER_MESSAGE
          example: HAN_METER_MESSAGE
        ts:
          type: integer
          description: Unix timestamp in milliseconds when the HAN reader received the meter message.
          format: int64
          example: 173568240000
        ic:
          type: number
          description: Active cumulative power in kwh.
          format: double
          example: 1000
        ec:
          type: number
          description: Active cumulative power out kwh.
          format: double
          example: 10
        ric:
          type: number
          description: Reactive cumulative energy imported in kVArh.
          format: double
          example: 1
        rec:
          type: number
          description: Reactive cumulative energy exported in kVArh.
          format: double
          example: 1
        p:
          type: array
          deprecated: true
          items:
            type: number
            format: double
          description: Deprecated. Active power in W. First item is sum on all phases, second item is phase 1, third item is phase 2, and fourth item is phase 3.
          example:
            - 1000
            - 300
            - 400
            - 300
        pi:
          type: array
          items:
            type: number
            format: double
          description: Active power import/consumption in W. First item is total, then phase 1..3.
          example:
            - 1000
            - 300
            - 400
            - 300
        pe:
          type: array
          items:
            type: number
            format: double
          description: Active power export/overproduction in W. First item is total, then phase 1..3.
          example:
            - 0
            - 0
            - 0
            - 0
        r:
          type: array
          deprecated: true
          items:
            type: number
            format: double
          description: Deprecated. Reactive power in VAr. First item is sum on all phases, second item is phase 1, third item is phase 2, and fourth item is phase 3.
          example:
            - 10
            - 3
            - 4
            - 3
        ri:
          type: array
          items:
            type: number
            format: double
          description: Reactive power import in VAr. First item is total, then phase 1..3.
          example:
            - 10
            - 3
            - 4
            - 3
        re:
          type: array
          items:
            type: number
            format: double
          description: Reactive power export in VAr. First item is total, then phase 1..3.
          example:
            - 0
            - 0
            - 0
            - 0
        u:
          type: array
          items:
            type: number
            format: double
          description: Voltage in V. Item 0 is phase 1, item 1 is phase 2, and item 2 is phase 3.
          example:
            - 220
            - 220
            - 220
        i:
          type: array
          items:
            type: number
            format: double
          description: Current in A. Item 0 is phase 1, item 1 is phase 2, and item 2 is phase 3.
          example:
            - 6
            - 6
            - 6
      required:
        - type
        - ts
        - ic
        - ec
        - ric
        - rec
        - p
        - pi
        - pe
        - r
        - ri
        - re
        - u
        - i
    HanMeterIdentityMessage:
      type: object
      description: Electricity meter identity fields extracted from HAN telegrams.
      additionalProperties: false
      properties:
        type:
          type: string
          description: Message discriminator. Always HAN_METER_IDENTITY_MESSAGE.
          enum:
            - HAN_METER_IDENTITY_MESSAGE
          example: HAN_METER_IDENTITY_MESSAGE
        manufacturerId:
          type: string
          description: Meter manufacturer identifier from telegram metadata.
          maxLength: 4
          example: KFM
        deviceType:
          type: string
          description: Meter device type identifier from telegram metadata.
          maxLength: 2
          example: E
        meterId:
          type: string
          description: Meter serial number or unique meter identifier.
          maxLength: 16
          example: A123456789012345
        meterName:
          type: string
          description: Meter name from telegram metadata.
          maxLength: 16
          example: AM550
      required:
        - type
        - manufacturerId
        - deviceType
        - meterId
        - meterName
    HanHealthMessage:
      type: object
      description: HAN reader health and runtime diagnostics message.
      additionalProperties: false
      properties:
        type:
          type: string
          description: Message discriminator. Always HAN_HEALTH_MESSAGE.
          enum:
            - HAN_HEALTH_MESSAGE
          example: HAN_HEALTH_MESSAGE
        uuid:
          type: string
          description: Unique stable identifier of the HAN reader.
          example: 7f2f8c1e-2c6d-4a25-b2b1-6f6a27d5f5de
        hostname:
          type: string
          description: HAN reader hostname used on the local network.
          example: Cozify-HAN-123-456
        free_heap_size:
          type: integer
          description: Current free heap memory in bytes.
          example: 182144
        minimum_free_heap_size:
          type: integer
          description: Lowest observed free heap memory since boot in bytes.
          example: 176320
        cpu_reset_reason:
          type: string
          description: Most recent reset cause reported by the ESP32 runtime.
          enum:
            - RST_UNKNOWN
            - RST_POWERON
            - RST_EXT
            - RST_SW
            - RST_PANIC
            - RST_INT_WDT
            - RST_TASK_WDT
            - RST_WDT
            - RST_DEEPSLEEP
            - RST_BROWNOUT
            - RST_SDIO
          example: RST_POWERON
        uptime_ms:
          type: integer
          format: int64
          description: Milliseconds elapsed since the HAN reader booted.
          example: 1234567
      required:
        - type
        - uuid
        - hostname
        - free_heap_size
        - minimum_free_heap_size
        - cpu_reset_reason
        - uptime_ms
    ScanStatus:
      type: string
      enum:
        - SCAN_RUNNING
        - SCAN_FAILED
        - SCAN_SUCCESS
    WifiAuthType:
      type: string
      enum:
        - OPEN
        - WEP
        - WPA_PSK
        - WPA2_PSK
        - WPA_WPA2_PSK
        - WPA2_ENTERPRISE
        - WPA3_PSK
        - WPA2_WPA3_PSK
        - WAPI_PSK
