{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://developers.dendosystems.com/downloads/renkei-processor-api-v1.0.schema.json",
  "title": "RENKEI Processor Uplink Protocol v1.0 (External Integration Profile)",
  "type": "object",
  "description": "Normative uplink message schemas for external TCP/JSON integrations in Phase 1. Unknown additive fields are allowed for forward compatibility.",
  "oneOf": [
    {
      "$ref": "#/$defs/hello_request_external"
    },
    {
      "$ref": "#/$defs/hello_response_external"
    },
    {
      "$ref": "#/$defs/ping_request_external"
    },
    {
      "$ref": "#/$defs/pong_response_external"
    },
    {
      "$ref": "#/$defs/query_state_request_external"
    },
    {
      "$ref": "#/$defs/query_state_response_external"
    },
    {
      "$ref": "#/$defs/subscribe_external"
    },
    {
      "$ref": "#/$defs/command_external"
    },
    {
      "$ref": "#/$defs/group_command_external"
    },
    {
      "$ref": "#/$defs/multi_motor_move_external"
    },
    {
      "$ref": "#/$defs/command_response_external"
    },
    {
      "$ref": "#/$defs/motor_state_external"
    },
    {
      "$ref": "#/$defs/group_state_external"
    },
    {
      "$ref": "#/$defs/registry_event_external"
    },
    {
      "$ref": "#/$defs/error_response_external"
    }
  ],
  "$defs": {
    "command_external": {
      "type": "object",
      "required": [
        "type",
        "motor_id",
        "op"
      ],
      "properties": {
        "type": {
          "const": "command"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "command_id": false,
        "motor_id": {
          "$ref": "#/$defs/motor_id"
        },
        "op": {
          "type": "string",
          "enum": [
            "move",
            "open",
            "close",
            "stop",
            "cycle_motion"
          ]
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "target_encoder": false,
        "direction": false,
        "pulses": false,
        "count": false,
        "speed_rpm": false
      },
      "allOf": [
        {
          "if": {
            "required": [
              "op"
            ],
            "properties": {
              "op": {
                "const": "move"
              }
            }
          },
          "then": {
            "required": [
              "target_percent"
            ]
          },
          "else": {
            "not": {
              "required": [
                "target_percent"
              ]
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "group_command_external": {
      "type": "object",
      "required": [
        "type",
        "group_id",
        "op"
      ],
      "properties": {
        "type": {
          "const": "group_command"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "command_id": false,
        "group_id": {
          "$ref": "#/$defs/group_id"
        },
        "op": {
          "type": "string",
          "enum": [
            "move",
            "stop"
          ]
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "target_encoder": false
      },
      "allOf": [
        {
          "if": {
            "required": [
              "op"
            ],
            "properties": {
              "op": {
                "const": "move"
              }
            }
          },
          "then": {
            "required": [
              "target_percent"
            ]
          },
          "else": {
            "not": {
              "required": [
                "target_percent"
              ]
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "multi_motor_move_external": {
      "type": "object",
      "required": [
        "type",
        "targets"
      ],
      "properties": {
        "type": {
          "const": "multi_motor_move"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "targets": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "$ref": "#/$defs/multi_motor_move_target"
          }
        },
        "op": false,
        "group_id": false,
        "motor_id": false,
        "target_percent": false,
        "target_encoder": false,
        "execute_at": false,
        "command_id": false
      },
      "additionalProperties": true
    },
    "command_response_external": {
      "type": "object",
      "required": [
        "type",
        "status"
      ],
      "properties": {
        "event_type": false,
        "type": {
          "const": "command_response"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "command_id": false,
        "status": {
          "type": "string",
          "enum": [
            "accepted",
            "rejected"
          ]
        },
        "retryable": {
          "type": "boolean"
        },
        "error_code": {
          "$ref": "#/$defs/command_rejection_error_code"
        },
        "results": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/multi_motor_move_result"
          }
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "status": {
                "const": "rejected"
              }
            }
          },
          "then": {
            "required": [
              "error_code",
              "retryable"
            ],
            "properties": {
              "results": {
                "not": {
                  "contains": {
                    "required": [
                      "status"
                    ],
                    "properties": {
                      "status": {
                        "const": "accepted"
                      }
                    }
                  }
                }
              }
            }
          },
          "else": {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "error_code"
                  ]
                },
                {
                  "required": [
                    "retryable"
                  ]
                }
              ]
            },
            "properties": {
              "results": {
                "contains": {
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "const": "accepted"
                    }
                  }
                }
              }
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "ping_request_external": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "ping"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        }
      },
      "additionalProperties": true
    },
    "pong_response_external": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "pong"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        }
      },
      "additionalProperties": true
    },
    "subscribe_external": {
      "type": "object",
      "description": "Bidirectional external subscribe request/success envelope; direction is defined by session lifecycle.",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "subscribe"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "filter": false,
        "status": false
      },
      "additionalProperties": true
    },
    "error_response_external": {
      "type": "object",
      "required": [
        "error_code",
        "error_message",
        "retryable"
      ],
      "properties": {
        "type": false,
        "event_type": false,
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "error_code": {
          "$ref": "#/$defs/protocol_error_code"
        },
        "error_message": {
          "type": "string",
          "minLength": 1
        },
        "error_reason": false,
        "retryable": {
          "type": "boolean"
        }
      },
      "allOf": [
        {
          "if": {
            "required": [
              "error_code"
            ],
            "properties": {
              "error_code": {
                "const": "response_too_large"
              }
            }
          },
          "then": {
            "properties": {
              "retryable": {
                "const": false
              }
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "motor_record_external": {
      "type": "object",
      "required": [
        "online",
        "display_name"
      ],
      "properties": {
        "online": {
          "type": "boolean"
        },
        "display_name": {
          "type": "string",
          "minLength": 1
        },
        "state": {
          "type": "string",
          "enum": [
            "opening",
            "closing",
            "stopped"
          ]
        },
        "percent": {
          "$ref": "#/$defs/percent"
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "travel_time_10ms": {
          "$ref": "#/$defs/time_10ms"
        },
        "travel_time": false,
        "endpoint_role": false,
        "motor_transport": false,
        "thread_power_class": false,
        "ap_id": false,
        "power_source": false,
        "battery_percent": false,
        "open_time_10ms": false,
        "close_time_10ms": false,
        "voltage_mv": false,
        "encoder_position": false,
        "encoder_current": false,
        "encoder_limit": false,
        "target_encoder": false,
        "run_flags": false,
        "err_flags": false,
        "rssi_dbm": false,
        "eui64": false,
        "name": false
      },
      "allOf": [
        {
          "not": {
            "anyOf": [
              {
                "required": [
                  "motor_transport"
                ]
              },
              {
                "required": [
                  "thread_power_class"
                ]
              },
              {
                "required": [
                  "ap_id"
                ]
              }
            ]
          }
        }
      ],
      "additionalProperties": true
    },
    "motor_state_external": {
      "type": "object",
      "required": [
        "event_type",
        "motor_id",
        "state",
        "online"
      ],
      "properties": {
        "event_type": {
          "const": "motor_state"
        },
        "protocol_version": false,
        "event_seq": false,
        "uptime_ms": false,
        "motor_id": {
          "$ref": "#/$defs/motor_id"
        },
        "motor_seq": false,
        "state": {
          "type": "string",
          "enum": [
            "opening",
            "closing",
            "stopped"
          ]
        },
        "online": {
          "type": "boolean"
        },
        "percent": {
          "$ref": "#/$defs/percent"
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "travel_time_10ms": {
          "$ref": "#/$defs/time_10ms"
        },
        "endpoint_role": false,
        "voltage_mv": false,
        "encoder_position": false,
        "encoder_current": false,
        "encoder_limit": false,
        "target_encoder": false,
        "open_time_10ms": false,
        "close_time_10ms": false,
        "travel_time": false,
        "run_flags": false,
        "err_flags": false,
        "battery_percent": false,
        "rssi_dbm": false,
        "motor_transport": false,
        "thread_power_class": false,
        "ap_id": false,
        "power_source": false,
        "eui64": false,
        "encoder": false,
        "sample_age_ms": false,
        "stale": false,
        "reason": false,
        "fault_subcode": false
      },
      "additionalProperties": true
    },
    "group_state_external": {
      "type": "object",
      "required": [
        "event_type",
        "group_id",
        "group_state"
      ],
      "properties": {
        "event_type": {
          "const": "group_state"
        },
        "protocol_version": false,
        "event_seq": false,
        "uptime_ms": false,
        "group_id": {
          "$ref": "#/$defs/group_id"
        },
        "group_state": {
          "type": "string",
          "enum": [
            "uniform",
            "moving",
            "mixed",
            "degraded"
          ]
        },
        "percent": {
          "$ref": "#/$defs/percent"
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "predicted": false
      },
      "additionalProperties": true
    },
    "group_record_external": {
      "type": "object",
      "required": [
        "display_name"
      ],
      "properties": {
        "display_name": {
          "type": "string",
          "minLength": 1
        },
        "members": false,
        "member_count": false,
        "name": false,
        "group_state": false,
        "percent": false,
        "target_percent": false
      },
      "additionalProperties": true
    },
    "group_snapshot_record_external": {
      "type": "object",
      "required": [
        "display_name",
        "group_state"
      ],
      "properties": {
        "display_name": {
          "type": "string",
          "minLength": 1
        },
        "group_state": {
          "type": "string",
          "enum": [
            "uniform",
            "moving",
            "mixed",
            "degraded"
          ]
        },
        "percent": {
          "$ref": "#/$defs/percent"
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "members": false,
        "member_count": false,
        "name": false
      },
      "additionalProperties": true
    },
    "group_snapshot_record_map_external": {
      "type": "object",
      "propertyNames": {
        "$ref": "#/$defs/group_id"
      },
      "additionalProperties": {
        "$ref": "#/$defs/group_snapshot_record_external"
      }
    },
    "motor_record_map_external": {
      "type": "object",
      "propertyNames": {
        "$ref": "#/$defs/motor_id"
      },
      "additionalProperties": {
        "$ref": "#/$defs/motor_record_external"
      }
    },
    "state_block_external": {
      "type": "object",
      "properties": {
        "motors": {
          "$ref": "#/$defs/motor_record_map_external"
        },
        "groups": {
          "$ref": "#/$defs/group_snapshot_record_map_external"
        },
        "settings": false,
        "runtime_counters": false
      },
      "anyOf": [
        {
          "required": [
            "motors"
          ]
        },
        {
          "required": [
            "groups"
          ]
        }
      ],
      "additionalProperties": true,
      "not": {
        "anyOf": [
          {
            "required": [
              "login_auth_state"
            ]
          },
          {
            "required": [
              "access_points"
            ]
          },
          {
            "required": [
              "discovered"
            ]
          }
        ]
      }
    },
    "query_state_request_external": {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "const": "query_state"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "scope": {
          "type": "string",
          "enum": [
            "all",
            "motors",
            "groups"
          ]
        }
      },
      "additionalProperties": true,
      "not": {
        "required": [
          "state"
        ]
      }
    },
    "registry_event_external": {
      "type": "object",
      "required": [
        "event_type",
        "change_type",
        "entity_type",
        "entity_id"
      ],
      "properties": {
        "event_type": {
          "const": "registry_event"
        },
        "protocol_version": false,
        "event_seq": false,
        "uptime_ms": false,
        "change_type": {
          "type": "string",
          "enum": [
            "created",
            "updated",
            "deleted"
          ]
        },
        "entity_type": {
          "type": "string",
          "enum": [
            "motor",
            "group"
          ]
        },
        "entity_id": {
          "type": "string",
          "minLength": 1
        },
        "entity": {
          "type": "object"
        }
      },
      "allOf": [
        {
          "if": {
            "required": [
              "change_type"
            ],
            "properties": {
              "change_type": {
                "enum": [
                  "created",
                  "updated"
                ]
              }
            }
          },
          "then": {
            "required": [
              "entity"
            ]
          }
        },
        {
          "if": {
            "required": [
              "entity_type"
            ],
            "properties": {
              "entity_type": {
                "const": "motor"
              }
            }
          },
          "then": {
            "properties": {
              "entity_id": {
                "$ref": "#/$defs/motor_id"
              }
            }
          }
        },
        {
          "if": {
            "required": [
              "entity_type"
            ],
            "properties": {
              "entity_type": {
                "const": "group"
              }
            }
          },
          "then": {
            "properties": {
              "entity_id": {
                "$ref": "#/$defs/group_id"
              }
            }
          }
        },
        {
          "if": {
            "required": [
              "entity_type",
              "entity"
            ],
            "properties": {
              "entity_type": {
                "const": "motor"
              }
            }
          },
          "then": {
            "properties": {
              "entity": {
                "$ref": "#/$defs/motor_record_external"
              }
            }
          }
        },
        {
          "if": {
            "required": [
              "entity_type",
              "entity"
            ],
            "properties": {
              "entity_type": {
                "const": "group"
              }
            }
          },
          "then": {
            "properties": {
              "entity": {
                "$ref": "#/$defs/group_record_external"
              }
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "hello_request_external": {
      "type": "object",
      "required": [
        "type",
        "protocol_version",
        "auth"
      ],
      "properties": {
        "type": {
          "const": "hello"
        },
        "protocol_version": {
          "$ref": "#/$defs/protocol_version"
        },
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "auth": {
          "type": "object",
          "required": [
            "token"
          ],
          "properties": {
            "mode": false,
            "token": {
              "type": "string",
              "minLength": 1
            }
          },
          "additionalProperties": true
        }
      },
      "additionalProperties": true
    },
    "hello_response_external": {
      "type": "object",
      "required": [
        "type",
        "protocol_version"
      ],
      "properties": {
        "type": {
          "const": "hello"
        },
        "protocol_version": {
          "$ref": "#/$defs/protocol_version"
        },
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "status": false
      },
      "additionalProperties": true,
      "not": {
        "required": [
          "auth"
        ]
      }
    },
    "query_state_response_external": {
      "type": "object",
      "required": [
        "type",
        "state"
      ],
      "properties": {
        "type": {
          "const": "query_state"
        },
        "protocol_version": false,
        "request_id": {
          "$ref": "#/$defs/request_id"
        },
        "state": {
          "$ref": "#/$defs/state_block_external"
        }
      },
      "additionalProperties": true
    },
    "command_rejection_error_code": {
      "type": "string",
      "enum": [
        "not_found",
        "conflict",
        "rate_limited",
        "internal_error"
      ]
    },
    "group_id": {
      "type": "string",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
    },
    "motor_id": {
      "type": "string",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
    },
    "multi_motor_move_result": {
      "type": "object",
      "required": [
        "motor_id",
        "status"
      ],
      "properties": {
        "motor_id": {
          "$ref": "#/$defs/motor_id"
        },
        "status": {
          "type": "string",
          "enum": [
            "accepted",
            "rejected"
          ]
        },
        "retryable": {
          "type": "boolean"
        },
        "error_code": {
          "$ref": "#/$defs/command_rejection_error_code"
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "status": {
                "const": "rejected"
              }
            }
          },
          "then": {
            "required": [
              "error_code",
              "retryable"
            ]
          },
          "else": {
            "not": {
              "anyOf": [
                {
                  "required": [
                    "error_code"
                  ]
                },
                {
                  "required": [
                    "retryable"
                  ]
                }
              ]
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "multi_motor_move_target": {
      "type": "object",
      "required": [
        "motor_id",
        "target_percent"
      ],
      "properties": {
        "motor_id": {
          "$ref": "#/$defs/motor_id"
        },
        "target_percent": {
          "$ref": "#/$defs/percent"
        },
        "op": false,
        "group_id": false,
        "target_encoder": false,
        "execute_at": false,
        "command_id": false
      },
      "additionalProperties": true
    },
    "percent": {
      "type": "number",
      "minimum": 0,
      "maximum": 100,
      "multipleOf": 0.01
    },
    "protocol_error_code": {
      "type": "string",
      "enum": [
        "invalid_message",
        "unsupported_version",
        "unauthorized",
        "forbidden",
        "response_too_large"
      ]
    },
    "protocol_version": {
      "type": "string",
      "const": "1.0"
    },
    "request_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "time_10ms": {
      "type": "integer",
      "minimum": 0,
      "maximum": 65535
    }
  }
}
