{
  "openapi": "3.1.1",
  "info": {
    "title": "RECOM Mobile API",
    "description": "## Error model\n\nFailures use RFC 9457 `application/problem+json`. Every body carries a stable lowercase dotted `code` (the value clients branch on), the W3C `traceId`, and a `correlationId`; validation failures add a per-field `errors` object. `status` and `code` are contract; `title` and `detail` are human-readable and may change.\n\n| Code | Status | Title |\n|---|---|---|\n| `assistant.answer_unavailable` | 502 | Assistant produced no answer |\n| `assistant.model_unavailable` | 503 | Assistant model temporarily unavailable |\n| `auth.continuation_expired` | 401 | Continuation expired |\n| `auth.forbidden` | 403 | Not permitted |\n| `auth.invalid_continuation_token` | 401 | Continuation token rejected |\n| `auth.invalid_credentials` | 401 | Authentication failed |\n| `auth.project_forbidden` | 403 | Project not available to this user |\n| `auth.projects_unavailable` | 503 | Project list temporarily unavailable |\n| `auth.provider_unavailable` | 503 | Authentication temporarily unavailable |\n| `auth.rate_limit_exceeded` | 429 | Too many attempts |\n| `auth.unauthorized` | 401 | Authentication required |\n| `controllers.command_equipment_not_fitted` | 409 | Equipment not fitted |\n| `controllers.command_forbidden` | 403 | Command not permitted for this user |\n| `controllers.command_layout_unsupported` | 409 | Command not supported by this firmware layout |\n| `controllers.command_model_unsupported` | 409 | Command not supported by this controller model |\n| `controllers.command_not_sendable` | 409 | Command declared but not sendable |\n| `controllers.command_partially_accepted` | 502 | Command only partially accepted |\n| `controllers.command_state_unknown` | 409 | Controller state unavailable |\n| `controllers.command_target_out_of_range` | 422 | Valve or program number out of range |\n| `controllers.command_transport_unavailable` | 503 | Command delivery service unavailable |\n| `controllers.command_value_out_of_range` | 422 | Value out of range for the device |\n| `controllers.controller_forbidden` | 403 | Controller not available to this user |\n| `controllers.controller_not_found` | 404 | Controller not found |\n| `controllers.data_unavailable` | 503 | Controller data temporarily unavailable |\n| `controllers.project_forbidden` | 403 | Project not available to this user |\n| `controllers.realtime_unavailable` | 503 | Controller real-time state temporarily unavailable |\n| `http.method_not_allowed` | 405 | Method not allowed |\n| `http.not_found` | 404 | Resource not found |\n| `http.unsupported_media_type` | 415 | Unsupported media type |\n| `logs.file_not_found` | 404 | Log file not found |\n| `push.controller_access_denied` | 403 | Controller access denied |\n| `push.event_not_allowed` | 400 | Push event is not allowed |\n| `push.invalid_registration` | 400 | Invalid push registration |\n| `push.invalid_subscription` | 400 | Invalid push subscription |\n| `push.no_authorized_controllers` | 400 | No authorized controllers |\n| `push.persistence_unavailable` | 503 | Push subscriptions temporarily unavailable |\n| `push.subscription_not_found` | 404 | Push subscription not found |\n| `push.test_send_disabled` | 403 | Push diagnostic sending is disabled |\n| `request.body_too_large` | 413 | Request body too large |\n| `request.malformed` | 400 | Request could not be read |\n| `request.validation_failed` | 400 | Request validation failed |\n| `server.unexpected` | 500 | Unexpected error |\n| `service_calls.controller_forbidden` | 403 | Controller not available to this user |\n| `service_calls.data_unavailable` | 503 | Service call data temporarily unavailable |\n| `service_calls.project_forbidden` | 403 | Project not available to this user |\n| `service_calls.service_call_not_found` | 404 | Service call not found |\n| `service_calls.unknown_code` | 400 | Value outside the service call vocabulary |\n",
    "contact": {
      "name": "Siema Tech Ltd.",
      "url": "https://www.siema.co.il/"
    },
    "version": "v1"
  },
  "paths": {
    "/api/v1/auth/sessions": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Sign in with RECO credentials",
        "description": "Verifies the username and password against the external RECO authentication service and returns a short-lived access token plus an opaque continuation token for automatic login. Invalid credentials return the same 401 regardless of whether the user exists. Anonymous, rate-limited.",
        "operationId": "CreateSession",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateSessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request could not be read (`request.malformed`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.malformed": {
                    "summary": "Request could not be read",
                    "value": {
                      "type": "https://recom.example/problems/request/malformed",
                      "title": "Request could not be read",
                      "status": 400,
                      "detail": "The request body or parameters could not be parsed.",
                      "instance": "/api/v1/auth/sessions",
                      "code": "request.malformed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/auth/sessions",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.malformed",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication failed (`auth.invalid_credentials`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.invalid_credentials": {
                    "summary": "Authentication failed",
                    "value": {
                      "type": "https://recom.example/problems/auth/invalid-credentials",
                      "title": "Authentication failed",
                      "status": 401,
                      "detail": "The supplied credentials could not be verified.",
                      "instance": "/api/v1/auth/sessions",
                      "code": "auth.invalid_credentials",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.invalid_credentials"
            ]
          },
          "413": {
            "description": "Request body too large (`request.body_too_large`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.body_too_large": {
                    "summary": "Request body too large",
                    "value": {
                      "type": "https://recom.example/problems/request/body-too-large",
                      "title": "Request body too large",
                      "status": 413,
                      "detail": "The request body exceeds the permitted size.",
                      "instance": "/api/v1/auth/sessions",
                      "code": "request.body_too_large",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.body_too_large"
            ]
          },
          "429": {
            "description": "Too many attempts (`auth.rate_limit_exceeded`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.rate_limit_exceeded": {
                    "summary": "Too many attempts",
                    "value": {
                      "type": "https://recom.example/problems/auth/rate-limit-exceeded",
                      "title": "Too many attempts",
                      "status": 429,
                      "detail": "Too many requests. Retry after the indicated delay.",
                      "instance": "/api/v1/auth/sessions",
                      "code": "auth.rate_limit_exceeded",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.rate_limit_exceeded"
            ]
          },
          "503": {
            "description": "Authentication temporarily unavailable (`auth.provider_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.provider_unavailable": {
                    "summary": "Authentication temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/auth/provider-unavailable",
                      "title": "Authentication temporarily unavailable",
                      "status": 503,
                      "detail": "The authentication service could not be reached. Try again shortly.",
                      "instance": "/api/v1/auth/sessions",
                      "code": "auth.provider_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.provider_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/auth/sessions/refresh": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Continue a session with the stored continuation token",
        "description": "Exchanges a valid continuation token for a fresh access token and a replacement continuation token bound to the same installation. The absolute session expiry set at credential login is never extended. The submitted token is stateless and is not individually consumed or revoked. Anonymous, rate-limited.",
        "operationId": "RefreshSession",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefreshSessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request could not be read (`request.malformed`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.malformed": {
                    "summary": "Request could not be read",
                    "value": {
                      "type": "https://recom.example/problems/request/malformed",
                      "title": "Request could not be read",
                      "status": 400,
                      "detail": "The request body or parameters could not be parsed.",
                      "instance": "/api/v1/auth/sessions/refresh",
                      "code": "request.malformed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/auth/sessions/refresh",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.malformed",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Continuation expired (`auth.continuation_expired`); Continuation token rejected (`auth.invalid_continuation_token`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.continuation_expired": {
                    "summary": "Continuation expired",
                    "value": {
                      "type": "https://recom.example/problems/auth/continuation-expired",
                      "title": "Continuation expired",
                      "status": 401,
                      "detail": "Reauthentication with credentials is required.",
                      "instance": "/api/v1/auth/sessions/refresh",
                      "code": "auth.continuation_expired",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "auth.invalid_continuation_token": {
                    "summary": "Continuation token rejected",
                    "value": {
                      "type": "https://recom.example/problems/auth/invalid-continuation-token",
                      "title": "Continuation token rejected",
                      "status": 401,
                      "detail": "The continuation token is not valid for this installation.",
                      "instance": "/api/v1/auth/sessions/refresh",
                      "code": "auth.invalid_continuation_token",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.continuation_expired",
              "auth.invalid_continuation_token"
            ]
          },
          "413": {
            "description": "Request body too large (`request.body_too_large`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.body_too_large": {
                    "summary": "Request body too large",
                    "value": {
                      "type": "https://recom.example/problems/request/body-too-large",
                      "title": "Request body too large",
                      "status": 413,
                      "detail": "The request body exceeds the permitted size.",
                      "instance": "/api/v1/auth/sessions/refresh",
                      "code": "request.body_too_large",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.body_too_large"
            ]
          },
          "429": {
            "description": "Too many attempts (`auth.rate_limit_exceeded`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.rate_limit_exceeded": {
                    "summary": "Too many attempts",
                    "value": {
                      "type": "https://recom.example/problems/auth/rate-limit-exceeded",
                      "title": "Too many attempts",
                      "status": 429,
                      "detail": "Too many requests. Retry after the indicated delay.",
                      "instance": "/api/v1/auth/sessions/refresh",
                      "code": "auth.rate_limit_exceeded",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.rate_limit_exceeded"
            ]
          }
        }
      }
    },
    "/api/v1/auth/me": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Describe the authenticated user",
        "description": "Returns the identity carried by the validated access token (user, customer, session) together with the deployment description of the answering process: API and build version, host environment, machine name, and the RECO database server and catalog it reads. No credential or connection-string secret is included. Requires a bearer access token.",
        "operationId": "GetCurrentUser",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetCurrentUserResponse"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/auth/me",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          }
        }
      }
    },
    "/api/v1/auth/projects": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "List the caller's authorized projects",
        "description": "Returns every project the authenticated user is authorized to work in, in one list ordered by project name, together with how often and how recently the user has opened each and whether they flagged it as a favorite. The entry matching the current access token is marked with isCurrent. A user who holds no project receives an empty list, not an error. The list is derived exclusively from the bearer token's identity; no request parameter can widen or change it. Reading the list does not change the current project or issue a new token.",
        "operationId": "ListUserProjects",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListUserProjectsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/auth/projects",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "503": {
            "description": "Project list temporarily unavailable (`auth.projects_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.projects_unavailable": {
                    "summary": "Project list temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/auth/projects-unavailable",
                      "title": "Project list temporarily unavailable",
                      "status": 503,
                      "detail": "The authorized project list could not be read. Try again shortly.",
                      "instance": "/api/v1/auth/projects",
                      "code": "auth.projects_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.projects_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/auth/projects/{projectId}/favorite": {
      "put": {
        "tags": [
          "Authentication"
        ],
        "summary": "Flag or unflag a project as a favorite",
        "description": "Stores the caller's favorite flag for one project, and answers 204 with no body; read the updated value from the project list. The flag belongs to the authenticated user, so the identity comes from the bearer token and the request carries only the project and the value. The project must be one the user is authorized to work in — otherwise the call is refused, whether or not the project exists. Sending the value a project already holds succeeds and changes nothing.",
        "operationId": "SetProjectFavorite",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "description": "The project to flag — a customerId from GET /api/v1/auth/projects. It must be one\r\nthis user is authorized to work in; anything else is refused with\r\nauth.project_forbidden, whether or not it exists.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetProjectFavoriteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/favorite",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/favorite",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`auth.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/auth/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/favorite",
                      "code": "auth.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.project_forbidden"
            ]
          },
          "503": {
            "description": "Project list temporarily unavailable (`auth.projects_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.projects_unavailable": {
                    "summary": "Project list temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/auth/projects-unavailable",
                      "title": "Project list temporarily unavailable",
                      "status": 503,
                      "detail": "The authorized project list could not be read. Try again shortly.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/favorite",
                      "code": "auth.projects_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.projects_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/auth/projects/{projectId}/entry": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Count one entry into a project",
        "description": "Raises the stored login counter for one project and answers 204 with no body; read the updated value as loginCount from the project list. The counter belongs to the authenticated user, so the identity comes from the bearer token and the request carries only the project and no body at all. The project must be one the user is authorized to work in — otherwise the call is refused, whether or not the project exists. Every call counts: this is not idempotent, and no server-side event stands behind it. Send it once when a person deliberately opens a project, never on a data read, a retry, a reconnect, or a background refresh — otherwise the counter measures traffic rather than visits. Selecting a project is still a client-side act that issues no token and changes no session; this call only records that it happened.",
        "operationId": "RecordProjectEntry",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "description": "The project that was opened — a customerId from GET /api/v1/auth/projects. It must\r\nbe one this user is authorized to work in; anything else is refused with\r\nauth.project_forbidden, whether or not it exists.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/entry",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/entry",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`auth.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/auth/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/entry",
                      "code": "auth.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.project_forbidden"
            ]
          },
          "503": {
            "description": "Project list temporarily unavailable (`auth.projects_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.projects_unavailable": {
                    "summary": "Project list temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/auth/projects-unavailable",
                      "title": "Project list temporarily unavailable",
                      "status": 503,
                      "detail": "The authorized project list could not be read. Try again shortly.",
                      "instance": "/api/v1/auth/projects/{projectId:long}/entry",
                      "code": "auth.projects_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.projects_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers": {
      "get": {
        "tags": [
          "Controllers"
        ],
        "summary": "List the caller's authorized controllers",
        "description": "Returns every controller of every model the authenticated user is authorized to see, in one deterministic list ordered by controller name. All items carry id/name plus metadata and location groups, including metadata.objectStatus (the raw RECO object-registry status code). LT lighting controllers add static area, connection, toll-gate and junction groups where configured. State is available only from the states endpoint or controller-states hub. Identity comes exclusively from the bearer token; a request may name which project to read and never which identity. By default the list covers the project the token was issued for. Pass projectId to read another project the same user is authorized to work in — the identity used inside that project is resolved on the server, and a project the user does not hold is refused rather than returned empty.",
        "operationId": "ListControllers",
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "description": "Read another project this user is authorized to work in — a customerId from GET\r\n/api/v1/auth/projects. Omit it to read the project the access token was issued\r\nfor, which performs no extra query. A project the user does not hold is refused\r\nwith controllers.project_forbidden, never returned empty.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListControllersResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "503": {
            "description": "Controller data temporarily unavailable (`controllers.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/states": {
      "post": {
        "tags": [
          "Controllers"
        ],
        "summary": "Refresh controller state, by id or across the authorized scope",
        "description": "Chooses its controllers with 'scope': 'explicit' (the default) refreshes the ids in controllerIds, and 'authorized' refreshes every controller the bearer token grants with no id list at all. Omitting 'scope' keeps the enumerated-ids behavior unchanged. Ids sent under 'authorized' are rejected rather than ignored, because dropping them would imply a narrowing the query does not apply. The 'source' query option selects realtime (the default) or history. The 'includeDetails' query option defaults to false, returning only id, name when available, and realtime globalState. Set it to true to add one exact deviceState object selected by its modelType discriminator. History has no global state and therefore requires includeDetails=true. Ids outside the caller's authorized set are silently omitted - the response never discloses whether such a controller exists. Identity comes exclusively from the bearer token; a request may name which project to read and never which identity. By default the refresh covers the project the token was issued for. Send projectId - a customerId from GET /api/v1/auth/projects - to refresh state in another project the same user is authorized to work in; it applies to both scopes, the identity used inside that project is resolved on the server, and a project the user does not hold is refused rather than answered with no state. GET /api/v1/controllers takes the same value as a query parameter, having no body to carry it. POST is used as the safe query shape for an id list; this operation writes nothing.",
        "operationId": "GetControllerStates",
        "parameters": [
          {
            "name": "source",
            "in": "query",
            "description": "State source: realtime for the live store, or history for the latest persisted snapshot. Defaults to realtime.",
            "schema": {
              "enum": [
                "realtime",
                "history"
              ],
              "type": "string",
              "default": "realtime"
            }
          },
          {
            "name": "includeDetails",
            "in": "query",
            "description": "Whether to include model-specific controller details. Defaults to false; history requires true.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "requestBody": {
          "description": "Whether to include the model-specific controller details. History reads require\ndetails because their persisted snapshots have no global-only representation.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetControllerStatesRequest"
              },
              "example": false
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetControllerStatesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/states",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/states",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/states",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "503": {
            "description": "Controller data temporarily unavailable (`controllers.data_unavailable`); Controller real-time state temporarily unavailable (`controllers.realtime_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/states",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.realtime_unavailable": {
                    "summary": "Controller real-time state temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/realtime-unavailable",
                      "title": "Controller real-time state temporarily unavailable",
                      "status": 503,
                      "detail": "The real-time state store could not be read. Retry shortly or request the history source.",
                      "instance": "/api/v1/controllers/states",
                      "code": "controllers.realtime_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.data_unavailable",
              "controllers.realtime_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/{controllerId}/valves": {
      "get": {
        "tags": [
          "Controllers"
        ],
        "summary": "List one controller's valve names by valve number",
        "description": "Returns the display names an operator gave one irrigation controller's valves, one item per valve number, ordered by number — the names to show next to the numbered valves that register state reports (its irrigation group's valves and valve activity carry numbers only). Names are operator text, most of it Hebrew, and valves that were never named are omitted. A controller outside the caller's authorized set answers with an empty list, never disclosing whether it exists; an empty list therefore also covers a controller with no named valves, such as a non-irrigation model. Identity comes exclusively from the bearer token; a request may name which project to read and never which identity. By default the read covers the project the token was issued for. Pass projectId to read a controller in another project the same user is authorized to work in — a project the user does not hold is refused rather than answered empty.",
        "operationId": "GetControllerValves",
        "parameters": [
          {
            "name": "controllerId",
            "in": "path",
            "description": "The controller whose valve names are returned — an id from GET /api/v1/controllers.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "projectId",
            "in": "query",
            "description": "Read a controller in another project this user is authorized to work in — a\r\ncustomerId from GET /api/v1/auth/projects. Omit it to read the project the\r\naccess token was issued for, which performs no extra query. A project the user\r\ndoes not hold is refused with controllers.project_forbidden, never returned\r\nempty.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetControllerValvesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/{controllerId:long}/valves",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/{controllerId:long}/valves",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/{controllerId:long}/valves",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "503": {
            "description": "Controller data temporarily unavailable (`controllers.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/{controllerId:long}/valves",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/{controllerId}": {
      "get": {
        "tags": [
          "Controllers"
        ],
        "summary": "Read one controller's full detail record",
        "description": "Returns the full detail record RECO keeps for one controller: the four free-text note fields, customer and agreement data, hardware and modem identity, SIM and phone numbers, power-supply code, install data and coordinates, plus the zone/region area assignment, the maintenance contractor, and the named water technician and supervisor. Codes are raw values - display labels are the client's. Wholly empty common groups are omitted. globalState is included when realtime state is available, and deviceState always identifies one exact model contract. A realtime outage omits realtime-derived values without hiding the SQL detail record. Free-text fields are operator text, most of it Hebrew, published verbatim. A controller in the caller's authorized set answers even when disabled; one outside it answers 403 controllers.controller_forbidden, and an id that exists nowhere answers 404 controllers.controller_not_found. Identity comes exclusively from the bearer token; a request may name which project to read and never which identity. By default the read covers the project the token was issued for. Pass projectId to read a controller in another project the same user is authorized to work in - a project the user does not hold is refused.",
        "operationId": "GetControllerDetails",
        "parameters": [
          {
            "name": "controllerId",
            "in": "path",
            "description": "The controller whose detail record is returned — an id from GET /api/v1/controllers.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "projectId",
            "in": "query",
            "description": "Read a controller in another project this user is authorized to work in — a\r\ncustomerId from GET /api/v1/auth/projects. Omit it to read the project the\r\naccess token was issued for, which performs no extra query. A project the user\r\ndoes not hold is refused with controllers.project_forbidden.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetControllerDetailsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/{controllerId:long}",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/{controllerId:long}",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Controller not available to this user (`controllers.controller_forbidden`); Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.controller_forbidden": {
                    "summary": "Controller not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/controller-forbidden",
                      "title": "Controller not available to this user",
                      "status": 403,
                      "detail": "The requested controller is not one this user may read.",
                      "instance": "/api/v1/controllers/{controllerId:long}",
                      "code": "controllers.controller_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/{controllerId:long}",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.controller_forbidden",
              "controllers.project_forbidden"
            ]
          },
          "404": {
            "description": "Controller not found (`controllers.controller_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.controller_not_found": {
                    "summary": "Controller not found",
                    "value": {
                      "type": "https://recom.example/problems/controllers/controller-not-found",
                      "title": "Controller not found",
                      "status": 404,
                      "detail": "No controller with the requested id exists.",
                      "instance": "/api/v1/controllers/{controllerId:long}",
                      "code": "controllers.controller_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.controller_not_found"
            ]
          },
          "503": {
            "description": "Controller data temporarily unavailable (`controllers.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/{controllerId:long}",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/{controllerId}/registers": {
      "get": {
        "tags": [
          "Controllers"
        ],
        "summary": "Read one controller's raw register file with the event directory's names",
        "description": "A diagnostics surface: every register of the controller's firmware layout with its stored value exactly as the store holds it — no scaling, no interpretation — joined server-side with the event directory, so each register carries its zone (statusBit, setBit, readOnly, setPoint, accumulator), its live event numbers, and — where the catalogue names it for the model — the confirmed parameter name and the reference's display labels. Digital-zone registers break out their sixteen bits; the decoded, typed view of the same registers is the model-details contract, and this route never replaces it. The 'source' query option selects the realtime store (default) or the latest persisted snapshot. A controller outside the caller's authorized set answers not found, without disclosing whether the id exists elsewhere. Identity comes exclusively from the bearer token; pass projectId to read a controller in another project the same user is authorized to work in.",
        "operationId": "GetControllerRegisters",
        "parameters": [
          {
            "name": "controllerId",
            "in": "path",
            "description": "The controller whose raw registers are returned — an id from GET /api/v1/controllers.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Where the registers come from: 'realtime' (default) reads the live store,\r\n'history' the latest persisted snapshot.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "projectId",
            "in": "query",
            "description": "Read a controller in another project this user is authorized to work in — a\r\ncustomerId from GET /api/v1/auth/projects. Omit it to read the project the\r\naccess token was issued for, which performs no extra query. A project the user\r\ndoes not hold is refused with controllers.project_forbidden.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetControllerRegistersResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/{controllerId:long}/registers",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/{controllerId:long}/registers",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/{controllerId:long}/registers",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "404": {
            "description": "Controller not found (`controllers.controller_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.controller_not_found": {
                    "summary": "Controller not found",
                    "value": {
                      "type": "https://recom.example/problems/controllers/controller-not-found",
                      "title": "Controller not found",
                      "status": 404,
                      "detail": "No controller with the requested id exists.",
                      "instance": "/api/v1/controllers/{controllerId:long}/registers",
                      "code": "controllers.controller_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.controller_not_found"
            ]
          },
          "503": {
            "description": "Controller data temporarily unavailable (`controllers.data_unavailable`); Controller real-time state temporarily unavailable (`controllers.realtime_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/{controllerId:long}/registers",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.realtime_unavailable": {
                    "summary": "Controller real-time state temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/realtime-unavailable",
                      "title": "Controller real-time state temporarily unavailable",
                      "status": 503,
                      "detail": "The real-time state store could not be read. Retry shortly or request the history source.",
                      "instance": "/api/v1/controllers/{controllerId:long}/registers",
                      "code": "controllers.realtime_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.data_unavailable",
              "controllers.realtime_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/event-catalog": {
      "get": {
        "tags": [
          "Controllers"
        ],
        "summary": "Describe the device events a realtime client can subscribe to",
        "description": "Returns every device event RECOM can name, grouped by controller model. Each entry carries the parameter name, how to read the value (valueKind), and where the value comes from: the register, the bit index within it (0 for analogue parameters), and which of the five register zones the address falls in (registerKind: StatusBit, SetBit, ReadOnly, SetPoint, Accumulator). Use it to build a realtime subscription without hard-coding numbers: an eventNumber plus its modelCode is exactly the key a SpecificEvents subscription names on the controller-states hub. Boolean parameters also carry offEventNumber — the number reported when the value turns off — and a subscription that wants both transitions must name both numbers. Analogue parameters have no off twin, so they omit offEventNumber. A model that is absent is not one that reports no events: it is one whose parameter names are not confirmed, and its events still arrive on the hub as Unclassified with their event number intact. Name a model in modelCode to get everything known about it instead: every event it names or that the Agam reference labels, resolved against the firmware layout given in layout (long, the 1066-register default, or short). Those entries carry displayLabels — the reference's own Hebrew and Latin UI text, unreviewed and machine-translated in places, useful for showing an operator something but never as an identifier or a substitute for parameterName. The catalogue is compiled device knowledge and identical for every caller, so it is safe to fetch once and cache for the life of a client session.",
        "operationId": "GetControllerEventCatalog",
        "parameters": [
          {
            "name": "modelCode",
            "in": "query",
            "description": "Limit the catalog to one controller model — the modelCode a controller reports, such\r\nas LT or DM. Omit it to return every model the catalog names.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "layout",
            "in": "query",
            "description": "Firmware register layout an event's address is resolved against: long (the\r\n1066-register default) or short. Omitting it uses long. Only meaningful together\r\nwith modelCode.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetEventCatalogResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/event-catalog",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/event-catalog",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          }
        }
      }
    },
    "/api/v1/push-subscriptions/options": {
      "get": {
        "tags": [
          "Push subscriptions"
        ],
        "summary": "Get notification subscription options",
        "description": "Returns the current caller's authorized controller IDs, Firebase applications, subscription modes, server-approved event keys, configured selection limits, and diagnostic-send capability. authorizedControllerIds is complete and unbounded - it is never truncated or refused for being long. maximumControllersPerSubscription bounds an explicit controller list only; a subscription with scope authorized is not size-limited. The caller identity is derived exclusively from the bearer token.",
        "operationId": "GetPushSubscriptionOptions",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetPushSubscriptionOptionsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid push subscription (`push.invalid_subscription`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.invalid_subscription": {
                    "summary": "Invalid push subscription",
                    "value": {
                      "type": "https://recom.example/problems/push/invalid-subscription",
                      "title": "Invalid push subscription",
                      "status": 400,
                      "detail": "The subscription mode or selected filters are not supported.",
                      "instance": "/api/v1/push-subscriptions/options",
                      "code": "push.invalid_subscription",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/push-subscriptions/options",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.invalid_subscription",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/push-subscriptions/options",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "503": {
            "description": "Push subscriptions temporarily unavailable (`push.persistence_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.persistence_unavailable": {
                    "summary": "Push subscriptions temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/push/persistence-unavailable",
                      "title": "Push subscriptions temporarily unavailable",
                      "status": 503,
                      "detail": "Push subscriptions could not be read or updated. Try again shortly.",
                      "instance": "/api/v1/push-subscriptions/options",
                      "code": "push.persistence_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.persistence_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/push-subscriptions": {
      "get": {
        "tags": [
          "Push subscriptions"
        ],
        "summary": "List the caller's notification subscriptions",
        "description": "Returns subscriptions owned by the authenticated caller. Firebase installation identifiers, their hashes, protected values, provider credentials, and delivery records are never returned.",
        "operationId": "ListPushSubscriptions",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListPushSubscriptionsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid push subscription (`push.invalid_subscription`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.invalid_subscription": {
                    "summary": "Invalid push subscription",
                    "value": {
                      "type": "https://recom.example/problems/push/invalid-subscription",
                      "title": "Invalid push subscription",
                      "status": 400,
                      "detail": "The subscription mode or selected filters are not supported.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.invalid_subscription",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.invalid_subscription",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "503": {
            "description": "Push subscriptions temporarily unavailable (`push.persistence_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.persistence_unavailable": {
                    "summary": "Push subscriptions temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/push/persistence-unavailable",
                      "title": "Push subscriptions temporarily unavailable",
                      "status": 503,
                      "detail": "Push subscriptions could not be read or updated. Try again shortly.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.persistence_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.persistence_unavailable"
            ]
          }
        }
      },
      "put": {
        "tags": [
          "Push subscriptions"
        ],
        "summary": "Create or update a notification subscription",
        "description": "Creates or updates the authenticated caller's subscription for one Firebase installation. The installation identifier is write-only and is never returned or logged. Scope authorized is the default: the request carries no controller ids and the server saves the caller's currently authorized controllers, however many that is - an authorized subscription has no size limit. Scope explicit requires controller ids and accepts at most maximumControllersPerSubscription of them, published by the options endpoint; that limit bounds what a client may send and never how many controllers a caller may be authorized for. Repeating this request with the same installation refreshes an authorized-controller snapshot.",
        "operationId": "UpsertPushSubscription",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertPushSubscriptionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpsertPushSubscriptionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Push event is not allowed (`push.event_not_allowed`); Invalid push registration (`push.invalid_registration`); Invalid push subscription (`push.invalid_subscription`); No authorized controllers (`push.no_authorized_controllers`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.event_not_allowed": {
                    "summary": "Push event is not allowed",
                    "value": {
                      "type": "https://recom.example/problems/push/event-not-allowed",
                      "title": "Push event is not allowed",
                      "status": 400,
                      "detail": "One or more selected events are not available for notifications.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.event_not_allowed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "push.invalid_registration": {
                    "summary": "Invalid push registration",
                    "value": {
                      "type": "https://recom.example/problems/push/invalid-registration",
                      "title": "Invalid push registration",
                      "status": 400,
                      "detail": "The Firebase app or installation registration is not supported.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.invalid_registration",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "push.invalid_subscription": {
                    "summary": "Invalid push subscription",
                    "value": {
                      "type": "https://recom.example/problems/push/invalid-subscription",
                      "title": "Invalid push subscription",
                      "status": 400,
                      "detail": "The subscription mode or selected filters are not supported.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.invalid_subscription",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "push.no_authorized_controllers": {
                    "summary": "No authorized controllers",
                    "value": {
                      "type": "https://recom.example/problems/push/no-authorized-controllers",
                      "title": "No authorized controllers",
                      "status": 400,
                      "detail": "The caller is not authorized for any controller, so an authorized-scope subscription would never match an event.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.no_authorized_controllers",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.event_not_allowed",
              "push.invalid_registration",
              "push.invalid_subscription",
              "push.no_authorized_controllers",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Controller access denied (`push.controller_access_denied`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.controller_access_denied": {
                    "summary": "Controller access denied",
                    "value": {
                      "type": "https://recom.example/problems/push/controller-access-denied",
                      "title": "Controller access denied",
                      "status": 403,
                      "detail": "One or more selected controllers cannot be used for notifications.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.controller_access_denied",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.controller_access_denied"
            ]
          },
          "503": {
            "description": "Push subscriptions temporarily unavailable (`push.persistence_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.persistence_unavailable": {
                    "summary": "Push subscriptions temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/push/persistence-unavailable",
                      "title": "Push subscriptions temporarily unavailable",
                      "status": 503,
                      "detail": "Push subscriptions could not be read or updated. Try again shortly.",
                      "instance": "/api/v1/push-subscriptions/",
                      "code": "push.persistence_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.persistence_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/push-subscriptions/{subscriptionId}": {
      "delete": {
        "tags": [
          "Push subscriptions"
        ],
        "summary": "Deactivate a notification subscription",
        "description": "Deactivates a subscription owned by the authenticated caller. An unknown ID and a subscription owned by another caller return the same not-found response.",
        "operationId": "DeletePushSubscription",
        "parameters": [
          {
            "name": "subscriptionId",
            "in": "path",
            "description": "Identifier of the subscription to delete, as returned by GET\r\n/api/v1/push-subscriptions. A subscription this caller does not own is answered as\r\nnot found.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Invalid push subscription (`push.invalid_subscription`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.invalid_subscription": {
                    "summary": "Invalid push subscription",
                    "value": {
                      "type": "https://recom.example/problems/push/invalid-subscription",
                      "title": "Invalid push subscription",
                      "status": 400,
                      "detail": "The subscription mode or selected filters are not supported.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}",
                      "code": "push.invalid_subscription",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.invalid_subscription",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "404": {
            "description": "Push subscription not found (`push.subscription_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.subscription_not_found": {
                    "summary": "Push subscription not found",
                    "value": {
                      "type": "https://recom.example/problems/push/subscription-not-found",
                      "title": "Push subscription not found",
                      "status": 404,
                      "detail": "The requested push subscription was not found.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}",
                      "code": "push.subscription_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.subscription_not_found"
            ]
          },
          "503": {
            "description": "Push subscriptions temporarily unavailable (`push.persistence_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.persistence_unavailable": {
                    "summary": "Push subscriptions temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/push/persistence-unavailable",
                      "title": "Push subscriptions temporarily unavailable",
                      "status": 503,
                      "detail": "Push subscriptions could not be read or updated. Try again shortly.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}",
                      "code": "push.persistence_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.persistence_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/push-subscriptions/unregister": {
      "post": {
        "tags": [
          "Push subscriptions"
        ],
        "summary": "Remove a Firebase installation subscription",
        "description": "Idempotently removes the authenticated caller's subscription for the supplied Firebase installation. The installation identifier is write-only and is never returned or logged.",
        "operationId": "UnregisterPushInstallation",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnregisterPushInstallationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Invalid push registration (`push.invalid_registration`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.invalid_registration": {
                    "summary": "Invalid push registration",
                    "value": {
                      "type": "https://recom.example/problems/push/invalid-registration",
                      "title": "Invalid push registration",
                      "status": 400,
                      "detail": "The Firebase app or installation registration is not supported.",
                      "instance": "/api/v1/push-subscriptions/unregister",
                      "code": "push.invalid_registration",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/push-subscriptions/unregister",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.invalid_registration",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/push-subscriptions/unregister",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "503": {
            "description": "Push subscriptions temporarily unavailable (`push.persistence_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.persistence_unavailable": {
                    "summary": "Push subscriptions temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/push/persistence-unavailable",
                      "title": "Push subscriptions temporarily unavailable",
                      "status": 503,
                      "detail": "Push subscriptions could not be read or updated. Try again shortly.",
                      "instance": "/api/v1/push-subscriptions/unregister",
                      "code": "push.persistence_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.persistence_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/push-subscriptions/{subscriptionId}/test": {
      "post": {
        "tags": [
          "Push subscriptions"
        ],
        "summary": "Queue a diagnostic notification",
        "description": "Queues a diagnostic notification for an enabled subscription owned by the authenticated caller. This operation is available only when diagnostic sending is enabled by configuration.",
        "operationId": "SendPushTestNotification",
        "parameters": [
          {
            "name": "subscriptionId",
            "in": "path",
            "description": "Identifier of the subscription to send the diagnostic notification to, as returned\r\nby GET /api/v1/push-subscriptions.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendPushTestNotificationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}/test",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}/test",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Push diagnostic sending is disabled (`push.test_send_disabled`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.test_send_disabled": {
                    "summary": "Push diagnostic sending is disabled",
                    "value": {
                      "type": "https://recom.example/problems/push/test-send-disabled",
                      "title": "Push diagnostic sending is disabled",
                      "status": 403,
                      "detail": "Diagnostic notification sending is not enabled for this environment.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}/test",
                      "code": "push.test_send_disabled",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.test_send_disabled"
            ]
          },
          "404": {
            "description": "Push subscription not found (`push.subscription_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.subscription_not_found": {
                    "summary": "Push subscription not found",
                    "value": {
                      "type": "https://recom.example/problems/push/subscription-not-found",
                      "title": "Push subscription not found",
                      "status": 404,
                      "detail": "The requested push subscription was not found.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}/test",
                      "code": "push.subscription_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.subscription_not_found"
            ]
          },
          "503": {
            "description": "Push subscriptions temporarily unavailable (`push.persistence_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "push.persistence_unavailable": {
                    "summary": "Push subscriptions temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/push/persistence-unavailable",
                      "title": "Push subscriptions temporarily unavailable",
                      "status": 503,
                      "detail": "Push subscriptions could not be read or updated. Try again shortly.",
                      "instance": "/api/v1/push-subscriptions/{subscriptionId:guid}/test",
                      "code": "push.persistence_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "push.persistence_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/service-calls": {
      "get": {
        "tags": [
          "Service calls"
        ],
        "summary": "List service calls",
        "description": "Returns the fault reports raised against the controllers this user is authorized\r\nto work in, newest first. By default it returns the open ones — everything that\r\nhas not been finished or cancelled — for the whole project; narrow it with a\r\ncontroller, a status filter or an opening-date range. Calls on controllers\r\noutside the caller's authorized set are never returned, and no refusal says so.\r\nThe read is bounded: at most 500 calls per request, 100 by default, and the\r\nresponse says when more matched than were returned. Identity comes exclusively\r\nfrom the bearer token; a request may name which project to read and never which\r\nidentity.",
        "operationId": "ListServiceCalls",
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "description": "Read another project this user is authorized to work in — a customerId from GET\r\n/api/v1/auth/projects. Omit it to read the project the access token was issued for,\r\nwhich performs no extra query. A project the user does not hold is refused with\r\nservice_calls.project_forbidden, never returned empty.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          },
          {
            "name": "controllerId",
            "in": "query",
            "description": "Only this controller's calls — an id from GET /api/v1/controllers.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Which calls to return: open (the default — neither finished nor cancelled), closed,\r\nor all.",
            "schema": {
              "enum": [
                "open",
                "closed",
                "all"
              ],
              "type": "string",
              "default": "open"
            }
          },
          {
            "name": "openedFrom",
            "in": "query",
            "description": "Only calls opened on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "openedTo",
            "in": "query",
            "description": "Only calls opened on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum calls to return, 1-500. Defaults to 100.",
            "schema": {
              "maximum": 500,
              "minimum": 1,
              "type": "integer",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListServiceCallsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/service-calls/",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/service-calls/",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`service_calls.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/service-calls/",
                      "code": "service_calls.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.project_forbidden"
            ]
          },
          "503": {
            "description": "Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/service-calls/",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.data_unavailable"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Service calls"
        ],
        "summary": "Open a service call on a controller",
        "description": "Reports a fault against one controller and answers 201 with the stored call,\r\nwhose Location header is the new call's own route. The call is recorded as\r\nopened by the authenticated user, so the request carries no identity; it may\r\nname which project to work in and nothing more. The controller must be one this\r\nuser is authorized to work in — otherwise the call is refused, whether or not\r\nthat controller exists. The status, fault equipment and technician must all\r\nappear in GET /api/v1/service-calls/vocabulary. The stored record is read back\r\nrather than echoed, because the opening date and the project are derived when\r\nthe call is stored.",
        "operationId": "OpenServiceCall",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenServiceCallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceCallResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`); Value outside the service call vocabulary (`service_calls.unknown_code`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/service-calls/",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  },
                  "service_calls.unknown_code": {
                    "summary": "Value outside the service call vocabulary",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/unknown-code",
                      "title": "Value outside the service call vocabulary",
                      "status": 400,
                      "detail": "One of the submitted codes is not part of the stored service call vocabulary. Read GET /api/v1/service-calls/vocabulary for the accepted values.",
                      "instance": "/api/v1/service-calls/",
                      "code": "service_calls.unknown_code",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed",
              "service_calls.unknown_code"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/service-calls/",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Controller not available to this user (`service_calls.controller_forbidden`); Project not available to this user (`service_calls.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.controller_forbidden": {
                    "summary": "Controller not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/controller-forbidden",
                      "title": "Controller not available to this user",
                      "status": 403,
                      "detail": "A service call can only be opened on a controller this user is authorized to work in.",
                      "instance": "/api/v1/service-calls/",
                      "code": "service_calls.controller_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "service_calls.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/service-calls/",
                      "code": "service_calls.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.controller_forbidden",
              "service_calls.project_forbidden"
            ]
          },
          "503": {
            "description": "Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/service-calls/",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/service-calls/vocabulary": {
      "get": {
        "tags": [
          "Service calls"
        ],
        "summary": "List the accepted service call values",
        "description": "Returns the closed catalogs a service call draws on — statuses, fault equipment,\r\nrecorded actions and replaced equipment — together with the technicians a call\r\nmay be assigned to. Opening or updating a call is refused unless its status,\r\nfault equipment and technician appear here, so this is the list a form should be\r\nbuilt from. Each entry carries the stored code, which is what a request sends\r\nback, and a name: for statuses, equipment and actions the name is a stable\r\ntranslation key to map to display text, while replaced equipment carries the\r\ncatalog's own text. The catalogs are the same for every user and are not\r\nspecific to a project.",
        "operationId": "GetServiceCallVocabulary",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetServiceCallVocabularyResponse"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/service-calls/vocabulary",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "503": {
            "description": "Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/service-calls/vocabulary",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/service-calls/{serviceCallId}": {
      "get": {
        "tags": [
          "Service calls"
        ],
        "summary": "Read one service call",
        "description": "Returns one fault report in full, including whatever treatment a technician has\r\nrecorded against it. A call number that does not exist and one that belongs to a\r\ncontroller outside the caller's authorized set answer the same way, so nothing\r\nhere can be used to discover which calls exist. Identity comes exclusively from\r\nthe bearer token; a request may name which project to read and never which\r\nidentity.",
        "operationId": "GetServiceCall",
        "parameters": [
          {
            "name": "serviceCallId",
            "in": "path",
            "description": "The call number, as returned by GET /api/v1/service-calls.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "projectId",
            "in": "query",
            "description": "Read a call in another project this user is authorized to work in — a customerId\r\nfrom GET /api/v1/auth/projects. Omit it to read the project the access token was\r\nissued for, which performs no extra query.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceCallResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`service_calls.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.project_forbidden"
            ]
          },
          "404": {
            "description": "Service call not found (`service_calls.service_call_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.service_call_not_found": {
                    "summary": "Service call not found",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/service-call-not-found",
                      "title": "Service call not found",
                      "status": 404,
                      "detail": "No service call with the requested id is available to this user.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.service_call_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.service_call_not_found"
            ]
          },
          "503": {
            "description": "Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.data_unavailable"
            ]
          }
        }
      },
      "put": {
        "tags": [
          "Service calls"
        ],
        "summary": "Update a service call's triage",
        "description": "Stores the status, priority, fault, description, assigned technician and notes\r\nof one call, and answers with the stored record. Every one of those is written,\r\nso send the current values for anything that should not change — an omitted\r\ntechnician clears the assignment. A call number that does not exist and one on a\r\ncontroller outside the caller's authorized set answer the same way. The status,\r\nfault equipment and technician must appear in GET\r\n/api/v1/service-calls/vocabulary. What a technician recorded doing, and the\r\nclosing date, are read-only here and cannot be set through this API.",
        "operationId": "UpdateServiceCall",
        "parameters": [
          {
            "name": "serviceCallId",
            "in": "path",
            "description": "The call number, as returned by GET /api/v1/service-calls.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateServiceCallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceCallResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`); Value outside the service call vocabulary (`service_calls.unknown_code`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  },
                  "service_calls.unknown_code": {
                    "summary": "Value outside the service call vocabulary",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/unknown-code",
                      "title": "Value outside the service call vocabulary",
                      "status": 400,
                      "detail": "One of the submitted codes is not part of the stored service call vocabulary. Read GET /api/v1/service-calls/vocabulary for the accepted values.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.unknown_code",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed",
              "service_calls.unknown_code"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`service_calls.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.project_forbidden"
            ]
          },
          "404": {
            "description": "Service call not found (`service_calls.service_call_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.service_call_not_found": {
                    "summary": "Service call not found",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/service-call-not-found",
                      "title": "Service call not found",
                      "status": 404,
                      "detail": "No service call with the requested id is available to this user.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.service_call_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.service_call_not_found"
            ]
          },
          "503": {
            "description": "Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/service-calls/{serviceCallId:long}",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "service_calls.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/assistant/queries": {
      "post": {
        "tags": [
          "Assistant"
        ],
        "summary": "Ask a natural-language question about the caller's controllers",
        "description": "Answers one question by letting the assistant model call a fixed, read-only set\r\nof tools - list projects, list controllers, read controller states, read one\r\ncontroller's details - each of which runs the same query the corresponding REST\r\nroute runs, under the caller's own identity. The model sees nothing the caller\r\ncould not read by hand and can reach no write. 'answer' is the model's text and\r\nmust be presented as such; 'controllers' lists the controllers the answer is\r\nabout, drawn only from rows the tools returned, so a client renders them without\r\nparsing prose; 'toolCalls' traces the tool rounds without their arguments.\r\nIdentity comes exclusively from the bearer token; a request may name which\r\nproject to ask about and never which identity. Send projectId - a customerId\r\nfrom GET /api/v1/auth/projects - to ask about another project the same user is\r\nauthorized to work in; a project the user does not hold is refused before the\r\nmodel is asked. Single-turn: there is no conversation state. Rate-limited per\r\nclient address, because each call spends provider tokens. Present only while\r\nFeatureManagement:AssistantQuery is enabled.",
        "operationId": "AskAssistant",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AskAssistantRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AskAssistantResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "429": {
            "description": "Too many attempts (`auth.rate_limit_exceeded`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.rate_limit_exceeded": {
                    "summary": "Too many attempts",
                    "value": {
                      "type": "https://recom.example/problems/auth/rate-limit-exceeded",
                      "title": "Too many attempts",
                      "status": 429,
                      "detail": "Too many requests. Retry after the indicated delay.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "auth.rate_limit_exceeded",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.rate_limit_exceeded"
            ]
          },
          "502": {
            "description": "Assistant produced no answer (`assistant.answer_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "assistant.answer_unavailable": {
                    "summary": "Assistant produced no answer",
                    "value": {
                      "type": "https://recom.example/problems/assistant/answer-unavailable",
                      "title": "Assistant produced no answer",
                      "status": 502,
                      "detail": "The assistant did not produce a usable answer for this question. Rephrase it or try again.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "assistant.answer_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "assistant.answer_unavailable"
            ]
          },
          "503": {
            "description": "Assistant model temporarily unavailable (`assistant.model_unavailable`); Controller data temporarily unavailable (`controllers.data_unavailable`); Controller real-time state temporarily unavailable (`controllers.realtime_unavailable`); Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "assistant.model_unavailable": {
                    "summary": "Assistant model temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/assistant/model-unavailable",
                      "title": "Assistant model temporarily unavailable",
                      "status": 503,
                      "detail": "The assistant model could not be reached. Try again shortly.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "assistant.model_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.realtime_unavailable": {
                    "summary": "Controller real-time state temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/realtime-unavailable",
                      "title": "Controller real-time state temporarily unavailable",
                      "status": 503,
                      "detail": "The real-time state store could not be read. Retry shortly or request the history source.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "controllers.realtime_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/assistant/queries",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "assistant.model_unavailable",
              "controllers.data_unavailable",
              "controllers.realtime_unavailable",
              "service_calls.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/assistant/queries/stream": {
      "post": {
        "tags": [
          "Assistant"
        ],
        "summary": "Ask a question and receive the answer as it is produced",
        "description": "The same question, tools and bounds as POST /api/v1/assistant/queries, delivered\r\nas Server-Sent Events (text/event-stream). Events: 'tool' as each tool round\r\nfinishes, 'delta' for each fragment of the answer text, and exactly one terminal\r\n'completed' (carrying the subject controllers, model and token usage) or\r\n'failed' (carrying a problem code). A failure that happens before the stream\r\nstarts is an ordinary problem response instead; once streaming has begun the\r\nstatus line is already sent, so 'failed' is the only way to report one. Treat\r\n'failed' as authoritative and discard any text that arrived before it. Send the\r\nbearer token as a header: this is POST precisely so the token never has to\r\ntravel in a query string. Present only while FeatureManagement:AssistantQuery is\r\nenabled.",
        "operationId": "AskAssistantStream",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AskAssistantRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "429": {
            "description": "Too many attempts (`auth.rate_limit_exceeded`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.rate_limit_exceeded": {
                    "summary": "Too many attempts",
                    "value": {
                      "type": "https://recom.example/problems/auth/rate-limit-exceeded",
                      "title": "Too many attempts",
                      "status": 429,
                      "detail": "Too many requests. Retry after the indicated delay.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "auth.rate_limit_exceeded",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.rate_limit_exceeded"
            ]
          },
          "502": {
            "description": "Assistant produced no answer (`assistant.answer_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "assistant.answer_unavailable": {
                    "summary": "Assistant produced no answer",
                    "value": {
                      "type": "https://recom.example/problems/assistant/answer-unavailable",
                      "title": "Assistant produced no answer",
                      "status": 502,
                      "detail": "The assistant did not produce a usable answer for this question. Rephrase it or try again.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "assistant.answer_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "assistant.answer_unavailable"
            ]
          },
          "503": {
            "description": "Assistant model temporarily unavailable (`assistant.model_unavailable`); Controller data temporarily unavailable (`controllers.data_unavailable`); Controller real-time state temporarily unavailable (`controllers.realtime_unavailable`); Service call data temporarily unavailable (`service_calls.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "assistant.model_unavailable": {
                    "summary": "Assistant model temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/assistant/model-unavailable",
                      "title": "Assistant model temporarily unavailable",
                      "status": 503,
                      "detail": "The assistant model could not be reached. Try again shortly.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "assistant.model_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.realtime_unavailable": {
                    "summary": "Controller real-time state temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/realtime-unavailable",
                      "title": "Controller real-time state temporarily unavailable",
                      "status": 503,
                      "detail": "The real-time state store could not be read. Retry shortly or request the history source.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "controllers.realtime_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "service_calls.data_unavailable": {
                    "summary": "Service call data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/service-calls/data-unavailable",
                      "title": "Service call data temporarily unavailable",
                      "status": 503,
                      "detail": "Service call data could not be read or written. Try again shortly.",
                      "instance": "/api/v1/assistant/queries/stream",
                      "code": "service_calls.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "assistant.model_unavailable",
              "controllers.data_unavailable",
              "controllers.realtime_unavailable",
              "service_calls.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/commands/capabilities": {
      "get": {
        "tags": [
          "Controller commands"
        ],
        "summary": "Read what this user may tell controllers to do",
        "description": "Returns the command capabilities this user's access level carries in the\r\nproject: operate, startProgrammedIrrigation, resetAccumulators and administer,\r\nor an empty list when the user may command nothing there. Use it to show or\r\nhide controls; it is advisory only, and every command is authorized again when\r\nit is sent. Identity comes exclusively from the bearer token; a request may\r\nname which project to read and never which identity. By default the read\r\ncovers the project the token was issued for. Pass projectId to read another\r\nproject the same user is authorized to work in — a project the user does not\r\nhold is refused.",
        "operationId": "GetControllerCommandCapabilities",
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "description": "Read the capabilities in another project this user is authorized to work in — a\r\ncustomerId from GET /api/v1/auth/projects. Omit it to read the project the\r\naccess token was issued for. A project the user does not hold is refused with\r\ncontrollers.project_forbidden.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetControllerCommandCapabilitiesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/commands/capabilities",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/commands/capabilities",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/commands/capabilities",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.project_forbidden"
            ]
          },
          "503": {
            "description": "Controller data temporarily unavailable (`controllers.data_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/commands/capabilities",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.data_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/controllers/{controllerId}/commands": {
      "post": {
        "tags": [
          "Controller commands"
        ],
        "summary": "Send one command to a controller",
        "description": "Sends one command — discriminated by type — to one controller, and answers 202\r\nonce the delivery service has accepted the register writes it became, with how\r\nmany writes there were and how long the service keeps trying to deliver them.\r\nEach write is one call to the service, in order; the first write the service\r\ndoes not take ends the command, and if any write before it was taken the\r\nanswer is 502 controllers.command_partially_accepted — the taken writes are\r\ndelivering, the rest were never sent. Accepted is not executed: observe the\r\neffect through the controller's state. When the controller's last stored state\r\nalready satisfies the request (a valve that is already open, a controller\r\nalready in service) the answer is 204 and nothing is sent.\r\n\r\nThe request names what should happen, never how: which register is written,\r\nwith which value and in what order, is decided on the server from the\r\ncontroller's model, firmware layout and last state report. Stored reports are\r\nused regardless of age or sync timestamp, and may differ from the device's\r\npresent state. A missing or unusable report is refused with\r\ncontrollers.command_state_unknown.\r\n\r\nEvery command is authorized at execution time: the controller must be one this\r\nuser is authorized to work in (403 controllers.controller_forbidden, or 404\r\nwhen no such controller exists), and the user's access level in the project\r\nmust carry the capability the command requires (403\r\ncontrollers.command_forbidden) — see GET /api/v1/controllers/commands/capabilities\r\nfor what this user may do. Identity comes exclusively from the bearer token; a\r\nrequest may name which project to work in and never which identity.",
        "operationId": "SubmitControllerCommand",
        "parameters": [
          {
            "name": "controllerId",
            "in": "path",
            "description": "The controller to command — an id from GET /api/v1/controllers.",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ControllerCommandRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitControllerCommandResponse"
                }
              }
            }
          },
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Request could not be read (`request.malformed`); Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.malformed": {
                    "summary": "Request could not be read",
                    "value": {
                      "type": "https://recom.example/problems/request/malformed",
                      "title": "Request could not be read",
                      "status": 400,
                      "detail": "The request body or parameters could not be parsed.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "request.malformed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.malformed",
              "request.validation_failed"
            ]
          },
          "401": {
            "description": "Authentication required (`auth.unauthorized`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.unauthorized": {
                    "summary": "Authentication required",
                    "value": {
                      "type": "https://recom.example/problems/auth/unauthorized",
                      "title": "Authentication required",
                      "status": 401,
                      "detail": "A valid access token is required for this resource.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "auth.unauthorized",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.unauthorized"
            ]
          },
          "403": {
            "description": "Command not permitted for this user (`controllers.command_forbidden`); Controller not available to this user (`controllers.controller_forbidden`); Project not available to this user (`controllers.project_forbidden`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.command_forbidden": {
                    "summary": "Command not permitted for this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-forbidden",
                      "title": "Command not permitted for this user",
                      "status": 403,
                      "detail": "This user's access level in the project does not include the capability the command requires.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.controller_forbidden": {
                    "summary": "Controller not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/controller-forbidden",
                      "title": "Controller not available to this user",
                      "status": 403,
                      "detail": "The requested controller is not one this user may read.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.controller_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.project_forbidden": {
                    "summary": "Project not available to this user",
                    "value": {
                      "type": "https://recom.example/problems/controllers/project-forbidden",
                      "title": "Project not available to this user",
                      "status": 403,
                      "detail": "The requested project is not one this user may work in.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.project_forbidden",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.command_forbidden",
              "controllers.controller_forbidden",
              "controllers.project_forbidden"
            ]
          },
          "404": {
            "description": "Controller not found (`controllers.controller_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.controller_not_found": {
                    "summary": "Controller not found",
                    "value": {
                      "type": "https://recom.example/problems/controllers/controller-not-found",
                      "title": "Controller not found",
                      "status": 404,
                      "detail": "No controller with the requested id exists.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.controller_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.controller_not_found"
            ]
          },
          "409": {
            "description": "Equipment not fitted (`controllers.command_equipment_not_fitted`); Command not supported by this firmware layout (`controllers.command_layout_unsupported`); Command not supported by this controller model (`controllers.command_model_unsupported`); Command declared but not sendable (`controllers.command_not_sendable`); Controller state unavailable (`controllers.command_state_unknown`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.command_equipment_not_fitted": {
                    "summary": "Equipment not fitted",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-equipment-not-fitted",
                      "title": "Equipment not fitted",
                      "status": 409,
                      "detail": "The controller is not fitted with the equipment the command addresses, such as a master valve, a fertilizer valve or a filter.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_equipment_not_fitted",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.command_layout_unsupported": {
                    "summary": "Command not supported by this firmware layout",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-layout-unsupported",
                      "title": "Command not supported by this firmware layout",
                      "status": 409,
                      "detail": "The controller's firmware layout does not carry the address this command writes.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_layout_unsupported",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.command_model_unsupported": {
                    "summary": "Command not supported by this controller model",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-model-unsupported",
                      "title": "Command not supported by this controller model",
                      "status": 409,
                      "detail": "The controller's model accepts no commands, or not this one.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_model_unsupported",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.command_not_sendable": {
                    "summary": "Command declared but not sendable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-not-sendable",
                      "title": "Command declared but not sendable",
                      "status": 409,
                      "detail": "This command is declared for the model but its device behaviour is not confirmed, so it is not sent.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_not_sendable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.command_state_unknown": {
                    "summary": "Controller state unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-state-unknown",
                      "title": "Controller state unavailable",
                      "status": 409,
                      "detail": "The controller has no usable state report for this command. Retry once the controller reports.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_state_unknown",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.command_equipment_not_fitted",
              "controllers.command_layout_unsupported",
              "controllers.command_model_unsupported",
              "controllers.command_not_sendable",
              "controllers.command_state_unknown"
            ]
          },
          "422": {
            "description": "Valve or program number out of range (`controllers.command_target_out_of_range`); Value out of range for the device (`controllers.command_value_out_of_range`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.command_target_out_of_range": {
                    "summary": "Valve or program number out of range",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-target-out-of-range",
                      "title": "Valve or program number out of range",
                      "status": 422,
                      "detail": "The valve or program number is outside what this controller has configured.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_target_out_of_range",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.command_value_out_of_range": {
                    "summary": "Value out of range for the device",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-value-out-of-range",
                      "title": "Value out of range for the device",
                      "status": 422,
                      "detail": "The value falls outside what the device register can hold.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_value_out_of_range",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.command_target_out_of_range",
              "controllers.command_value_out_of_range"
            ]
          },
          "429": {
            "description": "Too many attempts (`auth.rate_limit_exceeded`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "auth.rate_limit_exceeded": {
                    "summary": "Too many attempts",
                    "value": {
                      "type": "https://recom.example/problems/auth/rate-limit-exceeded",
                      "title": "Too many attempts",
                      "status": 429,
                      "detail": "Too many requests. Retry after the indicated delay.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "auth.rate_limit_exceeded",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "auth.rate_limit_exceeded"
            ]
          },
          "502": {
            "description": "Command only partially accepted (`controllers.command_partially_accepted`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.command_partially_accepted": {
                    "summary": "Command only partially accepted",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-partially-accepted",
                      "title": "Command only partially accepted",
                      "status": 502,
                      "detail": "The delivery service accepted some of the command's writes and refused the rest. Read the controller's state before retrying.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_partially_accepted",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.command_partially_accepted"
            ]
          },
          "503": {
            "description": "Command delivery service unavailable (`controllers.command_transport_unavailable`); Controller data temporarily unavailable (`controllers.data_unavailable`); Controller real-time state temporarily unavailable (`controllers.realtime_unavailable`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "controllers.command_transport_unavailable": {
                    "summary": "Command delivery service unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/command-transport-unavailable",
                      "title": "Command delivery service unavailable",
                      "status": 503,
                      "detail": "The service that delivers writes to controllers could not be reached, did not answer in time, or accepted nothing. As far as this API knows nothing was sent; read the controller's state before retrying.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.command_transport_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.data_unavailable": {
                    "summary": "Controller data temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/data-unavailable",
                      "title": "Controller data temporarily unavailable",
                      "status": 503,
                      "detail": "Controller data could not be read. Try again shortly.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.data_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  },
                  "controllers.realtime_unavailable": {
                    "summary": "Controller real-time state temporarily unavailable",
                    "value": {
                      "type": "https://recom.example/problems/controllers/realtime-unavailable",
                      "title": "Controller real-time state temporarily unavailable",
                      "status": 503,
                      "detail": "The real-time state store could not be read. Retry shortly or request the history source.",
                      "instance": "/api/v1/controllers/{controllerId:long}/commands",
                      "code": "controllers.realtime_unavailable",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "controllers.command_transport_unavailable",
              "controllers.data_unavailable",
              "controllers.realtime_unavailable"
            ]
          }
        }
      }
    },
    "/api/v1/logs": {
      "get": {
        "tags": [
          "Logs"
        ],
        "summary": "List backend log files",
        "description": "Returns the rolling compact-JSON log files currently on disk, newest first. Diagnostics endpoint: deliberately anonymous in Development (including local laptops); requires a bearer access token in every deployed environment.",
        "operationId": "ListLogFiles",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListLogFilesResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/logs/{fileName}": {
      "get": {
        "tags": [
          "Logs"
        ],
        "summary": "Read the tail of one log file",
        "description": "Returns the newest lines of the named rolling log file (default 200, maximum 2000 via ?tail=). Each line is one compact-JSON log event. Diagnostics endpoint: deliberately anonymous in Development (including local laptops); requires a bearer access token in every deployed environment.",
        "operationId": "GetLogFile",
        "parameters": [
          {
            "name": "fileName",
            "in": "path",
            "description": "Log file name exactly as returned by GET /api/v1/logs. The name is confined to the\r\nconfigured log directory; anything else is answered as not found and never echoed.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Tail",
            "in": "query",
            "description": "Newest lines to return; defaults to 200, maximum 2000.",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "example": 200
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetLogFileResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed (`request.validation_failed`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "request.validation_failed": {
                    "summary": "Request validation failed",
                    "value": {
                      "type": "https://recom.example/problems/request/validation-failed",
                      "title": "Request validation failed",
                      "status": 400,
                      "detail": "One or more request fields are invalid.",
                      "instance": "/api/v1/logs/{fileName}",
                      "code": "request.validation_failed",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde",
                      "errors": {
                        "fieldName": [
                          "Reason the field is invalid."
                        ]
                      }
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "request.validation_failed"
            ]
          },
          "404": {
            "description": "Log file not found (`logs.file_not_found`)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                },
                "examples": {
                  "logs.file_not_found": {
                    "summary": "Log file not found",
                    "value": {
                      "type": "https://recom.example/problems/logs/file-not-found",
                      "title": "Log file not found",
                      "status": 404,
                      "detail": "The requested log file does not exist.",
                      "instance": "/api/v1/logs/{fileName}",
                      "code": "logs.file_not_found",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "correlationId": "0190f1d2-3c4b-7a89-b012-3456789abcde"
                    }
                  }
                }
              }
            },
            "x-problem-codes": [
              "logs.file_not_found"
            ]
          }
        }
      }
    },
    "/api/v1/healthz/live": {
      "get": {
        "summary": "Liveness probe",
        "description": "Answers 200 Healthy whenever the process can serve requests. Process-only by design: no downstream dependency may fail liveness.",
        "operationId": "HealthLive",
        "responses": {
          "200": {
            "description": "The probe reports Healthy.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Healthy"
              }
            }
          },
          "503": {
            "description": "The probe reports Unhealthy.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Unhealthy"
              }
            }
          }
        }
      }
    },
    "/api/v1/healthz/ready": {
      "get": {
        "summary": "Readiness probe",
        "description": "Answers 200 Healthy when required read dependencies (the RECO read database) respond, otherwise 503 Unhealthy so orchestrators stop routing before users see failures. When the optional real-time store is configured, its availability reports Degraded-only and never fails readiness.",
        "operationId": "HealthReady",
        "responses": {
          "200": {
            "description": "The probe reports Healthy.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Healthy"
              }
            }
          },
          "503": {
            "description": "The probe reports Unhealthy.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Unhealthy"
              }
            }
          }
        }
      }
    },
    "/hubs/v1/controller-states": {
      "get": {
        "summary": "Controller states — realtime hub (SignalR over WebSocket)",
        "description": "Live controller state and device events, pushed over a persistent connection. This is not a REST\r\nendpoint: the GET below is the WebSocket upgrade, and every message after it is a SignalR JSON\r\nframe. Connect with any standard SignalR client and the same Bearer access token as the REST API\r\n(Authorization header, or the access_token query parameter, which this API accepts on hub paths\r\nonly). Server method: ReplaceControllerWindowAsync(ReplaceControllerWindowRequest) returns\r\nReplaceControllerWindowResponse and triggers the ControllerWindowResetAsync callback carrying\r\nthe sequence-1 snapshot of the authorized window. The request chooses its controllers with\r\n'scope': 'Explicit' (the default) watches the ids in controllerIds, bounded by\r\nMaximumWindowControllerIds; 'Authorized' watches every controller the window's project grants\r\nand carries no ids at all, so the request stays a fixed size however large that set is, and\r\nthere is no ceiling on how many controllers it may resolve to. Ids sent under 'Authorized' are\r\nrejected. 'stateDelivery' chooses what follows an event batch: 0 Full (the default) also sends\r\nthe authoritative ControllerStatesChangedAsync refresh, 1 Changed sends the batch alone and the\r\nserver makes no snapshot read for that window. Changed trades correction for traffic - the\r\nrefresh is the only message that reports values no event named - and its sequence-1 reset is\r\nnarrowed to match: id, metadata and globalState, with no registerState, because nothing would\r\ncorrect those registers afterwards. A Changed client reads registers from\r\nGET /api/v1/controllers/{controllerId}. Under Full the reset is the whole snapshot. Client\r\ncallbacks: ControllerWindowResetAsync, ControllerStatesChangedAsync,\r\nControllerEventsReceivedAsync, ControllerResyncRequiredAsync — their payload schemas are\r\npublished in components/schemas. Enum values cross the hub as numbers, unlike the REST surface\r\nwhere they are lowercase strings. Read the mappings below rather than the generated schemas: a\r\nschema generated from a named enum renders its members by name (valueKind is one), which is not\r\nwhat the wire carries. The mappings are: scope 0=Explicit, 1=Authorized; stateDelivery 0=Full,\r\n1=Changed; eventSubscription.mode 0=None, 1=All, 2=Categories, 3=SpecificEvents; categories\r\n5=System, 6=Elog, 7=Unclassified, 8=Parameter; events[].source 0=DeviceChange, 1=Elog;\r\nevents[].valueKind 0=Boolean, 1=Number, 2=SignedNumber, 3=EncodedTime, 4=MinutesFromMidnight,\r\n5=MonthDay, 6=Tenths; resync reason 0=SourceRepairFailed, 1=DeliveryOverflow,\r\n2=AuthorizationExpired, 3=DependencyUnavailable.\r\n\r\n**PROJECT SCOPE.** A user may work in several projects, and 'projectId' chooses which one this\r\nwindow watches. Omit it - the default - and the window uses the project the access token was\r\nissued for, which is what every window did before the field existed. Send one and the server\r\nresolves it, together with the caller's own identity, into the customer and user pair the\r\nauthorization read is made with; the identity used inside a project is derived on the server and\r\ncan never be supplied by a client, so a request may name a project but never an identity. List\r\nthe projects available with GET /api/v1/auth/projects. Resolution happens on every invocation,\r\nso switching project is a window replace and nothing else, and the connection itself is not\r\nproject-scoped. Both scopes honour it: 'Authorized' resolves to that project's whole controller\r\nset, and under 'Explicit' any id outside it is dropped rather than reported - compare\r\nauthorizedControllerCount against the number of ids sent to detect it. A project the caller may\r\nnot work in is refused with live.project_forbidden rather than answered with an empty window,\r\nbecause an empty window is indistinguishable from a project with nothing in it. The same REST\r\nselection is carried by GET /api/v1/controllers (?projectId=) and POST\r\n/api/v1/controllers/states (projectId in the body, not a query parameter).\r\n\r\n**DELIVERY ORDER.** Within one connection the order is fixed and worth relying on: the\r\nsequence-1 ControllerWindowResetAsync arrives before any event, a batch always precedes the\r\nControllerStatesChangedAsync refresh that belongs to it, and sequence numbers increase per\r\nconnection. Across connections the server publishes concurrently, so two clients watching the\r\nsame controller are served in no particular order relative to each other and neither waits for\r\nthe other. A batch and its refresh describe the same moment from two angles: the batch says\r\nwhich events fired, the refresh carries the authoritative register state read after them, so\r\napply the refresh rather than deriving state from the events. When that state read fails the\r\nbatch still arrives and is followed by ControllerResyncRequiredAsync instead of a refresh -\r\nnever by silence.\r\n\r\n**STATE GROUPS.** registerState carries the cross-model values every model reports (battery\r\nvoltage, power, door, firmware version) plus at most one per-model group, omitted entirely for\r\nthe models it does not apply to: lightingControl for LT (circuits, main switch, generator,\r\ncommunication controller, schedule), damControl for DM (cabinet faults and the four dams),\r\nirrigation for I1 (controller clock, valves, and the programs reconstructed from their start-\r\nday, start-after and start-with registers) and irrigationMaster for IP (fitted hardware, leak\r\ndetection, valve drive timings, and which slaves share the main valve and pumps). The irrigation\r\nvalve and program lists come from the 548-register firmware layout only, which is the one that\r\nstores the per-valve configuration.\r\n\r\n**SUBSCRIBING.** The subscription's 'categories' and 'events' arrays are optional and may be\r\nomitted or sent as null; both then read as empty. 'None' and 'All' require them empty,\r\n'Categories' requires 1 to 4 categories and no events, and 'SpecificEvents' requires 1 to 256\r\nkeys and no categories - each violation is a coded refusal, never a dropped field. 'None'\r\ndelivers no events (state refreshes still arrive). 'All' delivers everything for the window.\r\n'Categories' names whole categories. 'SpecificEvents' names exact keys as {source, modelCode,\r\neventNumber}: a device key needs a model code except event 6, the global-state event that\r\naddresses every model, and an Elog key must have a null model code. The model is taken from the\r\nauthorized SQL identity, so a client cannot widen its own scope through a key. Bounds are\r\nconfigured per deployment (LiveControllers): up to 4 categories and 256 event keys by default.\r\n\r\n**CATEGORIES.** A batch is grouped by controller, and every event carries a 'category'\r\ndiscriminator rather than landing in an array named after it. 'System' is the global-state\r\nevent (number 6) with state code, label and connectivity. 'Parameter' is a device event the\r\ncatalog resolved for the controller's model, carrying parameterName, valueKind, the raw\r\nintegerValue and the reading its kind implies (digitalValue, or textValue as HH:mm for a\r\nclock, dd-MM for a packed calendar day - the register packs day x 100 + month, so 27 March\r\nrenders as 27-03 - or a scaled decimal such as 12.4 for tenths). 'Unclassified' is a device\r\nevent with no catalog entry: number and value only. 'Elog' is reserved - ELOG ingestion is\r\nnot implemented, so no elog event arrives today. Category values 0-4 were DigitalInput,\r\nDigitalOutput, AnalogInput, AnalogOutput and Accumulation; they were withdrawn because\r\nnothing ever produced them, and the remaining members keep their original numbers so an\r\nexisting subscription still means what it meant. What those five were really describing was\r\nthe register zone an event addresses, which is a property of the number rather than of the\r\ndelivery, and is published per parameter as registerKind on\r\nGET /api/v1/controllers/event-catalog.\r\n\r\n**BATCH SHAPE (schema 2).** ControllerEventsReceivedAsync carries {schemaVersion, windowId,\r\nbatchSequence, publishedAtUtc, controllers[]}. Each entry is\r\n{id, modelCode, reportedAtUtc, globalState?, registerState?, parameters, events[]} and is the\r\nunit a client merges: replace globalState, spread registerState onto the state it holds,\r\nspread parameters into its own reported map, and the events that caused them are in the same\r\nobject with no lookup by id. In registerState a member is absent when this batch did not\r\nreport it - the opposite of the reset and the refresh, where an absent or null value means\r\nthe model does not report it - so a batch merges by spreading and a refresh by replacing.\r\n'parameters' is keyed by the catalogue parameter name and carries the event that reported\r\neach value plus rawValue, the payload's own Val verbatim. Two bounds are deliberate: only\r\nevents this window's subscription delivered are projected, so a filtered event never\r\nreappears as state; and only catalogued events name a parameter, so an uncatalogued event\r\nleaves its controller present with an empty 'parameters' rather than a guessed name.\r\nSchema 1 published four category arrays plus a separate states[] list. It repeated each\r\nevent's controllerId and modelCode, shipped two permanently empty arrays on every frame,\r\nand made a client join a state back to its events by id; the grouped shape says the same\r\nthings once. Subscribing is unaffected - Categories mode has always been a server-side\r\nfilter rather than a wire shape.\r\n\r\n**ENVELOPE FIELDS.** Every event carries envelopeIndex and envelopeSource, the Idx and Src of\r\nthe device.change envelope it arrived in, verbatim. envelopeIndex is the source's per-controller\r\nframe counter (consecutive frames for one controller carry consecutive values) and is not\r\ncomparable across controllers; envelopeSource is opaque and every observed frame carries 1. Both\r\nare provenance, not data: their one structural use is the deterministic eventId that makes a\r\nreplayed frame deduplicate. They were named legacyIndex and legacySource until 2026-08-31.\r\n\r\n**EVENT NUMBERS.** Event 6 is the model-independent global state. Every other number is a\r\nregister address: a block of numbers covers a run of registers, sixteen numbers per register for\r\nthe bit zones and one per register for the analogue zones, and every digital parameter has an\r\noff number exactly a hundred above its on number addressing the same bit. The catalog names\r\nparameters for LT (57 parameters) and DM (46 parameters). LT covers the 700s and 800s (power,\r\ndoor, general alarm, communication fault, main-switch position, per-circuit on and error, manual\r\nlight control, generator, water level), 3102/3202 and 3104/3204 for the communication\r\ncontroller, 1501-1652 for command latches and circuit enablement, 1701-1706 for the clock,\r\nsunrise, sunset and firmware version, 1801-1812 for configuration, and 1901-1904 for the\r\ngenerator hour and start counters. DM covers 701-716 for the cabinet, 717-780 and 1517-1567 for\r\nthe four dams' limit switches and control latches, 3102/3104 for the communication controller,\r\nand 1701/1801/1802/1901 for battery, configuration and accumulation. The same number means\r\ndifferent things on different models, because it is an address rather than an identifier: 717 is\r\nmainSwitchLocalControl on LT and dam1Open on DM. A model that is not in the catalog still\r\ndelivers its events - they arrive Unclassified with the number intact - it simply has no\r\nconfirmed parameter names. Fetch GET /api/v1/controllers/event-catalog to build a SpecificEvents\r\nsubscription from data instead of hard-coding numbers; an entry whose cadence is continuous (I1's\r\nmeter input lines, 733-736) is a contact re-reported about once a second while water moves, so\r\nexpect a stream on both twins rather than a change, and take it from the batch rather than the\r\nrefresh. Failures surface as HubException messages\r\nwith stable lowercase dotted codes (live.*, sql.*, redis.*), never as RFC 9457 problem\r\ndocuments. SignalR wraps them: the completion frame's error reads \\ + , so take the code from\r\nafter the HubException marker. A window-validation failure keeps its colon-separated detail list\r\nafter the code (live.window_invalid:<codes>). A refusal and an outage never share a code:\r\nlive.project_forbidden means the project is not one this user may work in and retrying will not\r\nhelp, while live.project_unavailable means the resolution itself could not be read and the same\r\nrequest may succeed on retry.\r\n\r\n**CALLBACK PAYLOADS.** ControllerWindowResetAsync and ControllerStatesChangedAsync carry\r\n{schemaVersion, windowId, sequence, controllers[]}; each controller is {id, metadata{modelCode,\r\nobjectStatus{code,name}}, globalState{code,name,isConnected}, registerState}. The reset is\r\nalways sequence 1 and defines the window's membership - a controller absent from it is not being\r\nwatched. In these two, registerState carries every member with null where the model does not\r\nreport it. ControllerEventsReceivedAsync carries {schemaVersion, windowId, batchSequence,\r\npublishedAtUtc} plus the four category arrays and states[]. Every event in those arrays carries\r\neventId, controllerId, modelCode, occurredAtUtc, eventNumber, envelopeIndex and envelopeSource,\r\nthen its category's own members: stateCode/stateName/isConnected for System;\r\nparameterName/valueKind/integerValue plus digitalValue or textValue for Parameter;\r\ntextValue/numericValue for Unclassified; isStart/eventCode/eventDescription/actionInstructions\r\nfor Elog. In states[] a member is absent when the batch did not report it, which is the opposite\r\nof the two payloads above, so merge states by spreading and apply a refresh by replacing.\r\nControllerResyncRequiredAsync carries {windowId, reason} and nothing else; act on it by\r\nreplacing the window, never by patching.",
        "operationId": "ControllerStatesHub",
        "requestBody": {
          "description": "Argument of the ReplaceControllerWindowAsync invocation. Sent as a SignalR JSON invocation frame, not as an HTTP body.",
          "content": {
            "application/json": {
              "schema": {
                "required": [
                  "windowId",
                  "eventSubscription"
                ],
                "type": "object",
                "properties": {
                  "windowId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "projectId": {
                    "pattern": "^-?(?:0|[1-9]\\d*)$",
                    "type": [
                      "null",
                      "integer",
                      "string"
                    ],
                    "description": "Which project the window watches. Omit it — the default — to watch the project the\naccess token was issued for, which is what every window did before this field existed.\nA project the signed-in user is not authorized to work in is refused; the identity used\ninside a project is resolved on the server and can never be supplied by a client.",
                    "format": "int64"
                  },
                  "scope": {
                    "enum": [
                      "explicit",
                      "authorized"
                    ],
                    "description": "How a live window chooses its controllers. Crosses the hub as a number like every other\nhub enum: `0 = Explicit` (the default when omitted), `1 = Authorized`."
                  },
                  "controllerIds": {
                    "type": "array",
                    "items": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "integer",
                        "string"
                      ],
                      "format": "int64"
                    },
                    "description": "Required for `Explicit`; must be empty for `Authorized`."
                  },
                  "eventSubscription": {
                    "required": [
                      "mode"
                    ],
                    "type": "object",
                    "properties": {
                      "mode": {
                        "enum": [
                          "none",
                          "all",
                          "categories",
                          "specificEvents"
                        ]
                      },
                      "categories": {
                        "type": "array",
                        "items": {
                          "enum": [
                            "system",
                            "elog",
                            "unclassified",
                            "parameter"
                          ],
                          "description": "Categories an event can be published under, and therefore the ones a Categories\nsubscription can select."
                        },
                        "description": "Named categories, for `Categories` mode; empty otherwise."
                      },
                      "events": {
                        "type": "array",
                        "items": {
                          "required": [
                            "source",
                            "modelCode",
                            "eventNumber"
                          ],
                          "type": "object",
                          "properties": {
                            "source": {
                              "enum": [
                                "deviceChange",
                                "elog"
                              ],
                              "description": "Which stream an event came from. Crosses both the hub and REST as the name below."
                            },
                            "modelCode": {
                              "type": [
                                "null",
                                "string"
                              ]
                            },
                            "eventNumber": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "format": "int32"
                            }
                          }
                        },
                        "description": "Exact event keys, for `SpecificEvents` mode; empty otherwise."
                      }
                    }
                  },
                  "stateDelivery": {
                    "enum": [
                      "full",
                      "changed"
                    ],
                    "description": "What a window wants after an event batch. Crosses the hub as a number like every other\nhub enum: `0 = Full` (the default when omitted), `1 = Changed`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "101": {
            "description": "WebSocket upgrade accepted; the SignalR handshake follows."
          },
          "200": {
            "description": "Completion frame of ReplaceControllerWindowAsync. A sequence-1 ControllerWindowResetAsync callback follows it.",
            "content": {
              "application/json": {
                "schema": {
                  "required": [
                    "windowId",
                    "authorizedControllerCount",
                    "leaseExpiresAtUtc"
                  ],
                  "type": "object",
                  "properties": {
                    "windowId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "authorizedControllerCount": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "integer",
                        "string"
                      ],
                      "format": "int32"
                    },
                    "leaseExpiresAtUtc": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token."
          }
        },
        "x-signalr-invocation": "ReplaceControllerWindowAsync",
        "x-signalr-callbacks": {
          "ControllerWindowResetAsync": "#/components/schemas/ControllerWindowResetResponse",
          "ControllerStatesChangedAsync": "#/components/schemas/ControllerStatesChangedResponse",
          "ControllerEventsReceivedAsync": "#/components/schemas/ControllerEventBatchResponse",
          "ControllerResyncRequiredAsync": "#/components/schemas/ControllerResyncRequiredResponse"
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AskAssistantRequest": {
        "type": "object",
        "properties": {
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Which project the question is about. Omit it — the default — to ask about the project\nthe access token was issued for, which performs no extra query. A project the caller\ndoes not hold is refused before the model is asked. It travels in the body because\nthis call already has one; `GET /api/v1/controllers` takes the same value as\n`?projectId=`.",
            "format": "int64",
            "example": 88
          },
          "question": {
            "type": "string",
            "description": "The question, 1–1000 characters. Answered from the caller's own data only.",
            "example": "Which lighting controllers in Netanya are disconnected?"
          }
        },
        "description": "One natural-language question about the caller's controllers. User and customer scope\nalways come from the bearer token, never from the request."
      },
      "AskAssistantResponse": {
        "required": [
          "answer",
          "controllers",
          "toolCalls"
        ],
        "type": "object",
        "properties": {
          "answer": {
            "type": "string"
          },
          "controllers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssistantControllerItemResponse"
            }
          },
          "toolCalls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssistantToolCallResponse"
            }
          },
          "model": {
            "type": [
              "null",
              "string"
            ],
            "description": "Model name the provider reported, when it reported one."
          },
          "usage": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AssistantUsageResponse"
              }
            ]
          },
          "serviceCallDraft": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "A service call the assistant filled in for the operator to confirm, when the question\nasked to raise one. Nothing has been written — the assistant reads and drafts, and the\ncall is opened only when a client submits it to POST /api/v1/service-calls.",
                "$ref": "#/components/schemas/AssistantServiceCallDraftResponse"
              }
            ]
          }
        },
        "description": "The model's answer, the controllers it is about, and the tool rounds it took."
      },
      "AssistantControllerItemResponse": {
        "required": [
          "id"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "globalState": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerGlobalStateResponse"
              }
            ]
          }
        },
        "description": "One controller the answer is about. Global state is present only when a states tool\nactually read it, so an absent value means \"not looked up\", never \"not connected\"."
      },
      "AssistantServiceCallDraftResponse": {
        "required": [
          "priority",
          "missing",
          "isReady"
        ],
        "type": "object",
        "properties": {
          "controllerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "controllerName": {
            "type": [
              "null",
              "string"
            ]
          },
          "faultEquipmentCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "faultEquipmentName": {
            "type": [
              "null",
              "string"
            ]
          },
          "faultDescription": {
            "type": [
              "null",
              "string"
            ]
          },
          "priority": {
            "type": "string",
            "description": "normal, urgent or critical."
          },
          "statusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "statusName": {
            "type": [
              "null",
              "string"
            ]
          },
          "assignedTechnicianId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "assignedTechnicianName": {
            "type": [
              "null",
              "string"
            ]
          },
          "notesForTechnician": {
            "type": [
              "null",
              "string"
            ]
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The fields still needed before the draft can be opened as a call."
          },
          "isReady": {
            "type": "boolean",
            "description": "True when nothing is missing and every code is one the stored vocabulary holds."
          }
        },
        "description": "A service call the assistant prepared for the operator to confirm. Present only when the\nquestion asked for one."
      },
      "AssistantToolCallResponse": {
        "required": [
          "name",
          "durationMs"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "durationMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          }
        },
        "description": "One tool round, in order. Arguments are never echoed: they can repeat operator-entered text."
      },
      "AssistantUsageResponse": {
        "required": [
          "inputTokens",
          "outputTokens"
        ],
        "type": "object",
        "properties": {
          "inputTokens": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "outputTokens": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int64"
          }
        },
        "description": "Token counts the provider reported for the exchange, when it reported any."
      },
      "AuthenticatedUserResponse": {
        "required": [
          "id",
          "username",
          "customerId",
          "customerName"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "username": {
            "type": "string"
          },
          "customerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "customerName": {
            "type": "string"
          }
        },
        "description": "Verified identity summary shared by the authentication use cases that return tokens.\nFeature-level because CreateSession and RefreshSession publish the identical shape."
      },
      "ControllerAccumulatorTarget": {
        "enum": [
          "controllerIrrigation",
          "controllerWaterLeak",
          "controllerFertilizerLeak",
          "controllerRinses",
          "valveIrrigation",
          "valveFertilizer"
        ],
        "description": "Which accumulating total a reset zeroes. A closed list because every member is a register\nthe device set aside for one named total; there is no \"any accumulator\" case, and offering\none would be an arbitrary-register write."
      },
      "ControllerAreaResponse": {
        "type": "object",
        "properties": {
          "districtName": {
            "type": [
              "null",
              "string"
            ]
          },
          "settlementName": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "additionalProperties": false
      },
      "ControllerCodedState": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The raw value, as its source reports it.",
            "format": "int32"
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
          }
        },
        "description": "A value that is a code from a confirmed vocabulary, published as the pair the global\nstate already uses: the raw code stays authoritative, the name is the vocabulary's fixed\nlabel, and an unknown code keeps the name null rather than guess.\nMost are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin.",
        "x-controller-values": {
          "code": {
            "kind": "number",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "Owning coded register or data column",
            "events": [ ],
            "evidence": "contract.coded-state"
          },
          "name": {
            "kind": "codedState",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "Confirmed vocabulary for the owning code",
            "events": [ ],
            "evidence": "contract.coded-state"
          }
        }
      },
      "ControllerCommandCapability": {
        "enum": [
          "operate",
          "startProgrammedIrrigation",
          "resetAccumulators",
          "administer"
        ],
        "description": "What a caller may tell a controller to do, as a closed set of capabilities. A command\nrequires exactly one of them, decided by ControllerCommandCapabilityRules;\nwhich access level holds which is deployment configuration, resolved at execution time and\nnever frozen into a token."
      },
      "ControllerCommandRequest": {
        "required": [
          "type"
        ],
        "type": "object",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ControllerCommandRequestSetControllerEnabledCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestStartValveCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestStopValveCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestOpenValveManuallyCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestCloseValveManuallyCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestSetProgramStateCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestSetMasterValveStateCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestSetFilterValveStateCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestResetControllerErrorsCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestResetValveErrorCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestRestartControllerCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestRestartSystemsCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestResetAccumulatorCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestAdjustRemainingStateCommandRequest"
          },
          {
            "$ref": "#/components/schemas/ControllerCommandRequestSetOperatingModeCommandRequest"
          }
        ],
        "additionalProperties": false,
        "description": "One command for a controller, discriminated by `type`. Each type carries only the\nfields that command needs; a request never names a register, a method code or a raw value\nto write, because those are decided on the server from what the controller reports.",
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "setControllerEnabled": "#/components/schemas/ControllerCommandRequestSetControllerEnabledCommandRequest",
            "startValve": "#/components/schemas/ControllerCommandRequestStartValveCommandRequest",
            "stopValve": "#/components/schemas/ControllerCommandRequestStopValveCommandRequest",
            "openValveManually": "#/components/schemas/ControllerCommandRequestOpenValveManuallyCommandRequest",
            "closeValveManually": "#/components/schemas/ControllerCommandRequestCloseValveManuallyCommandRequest",
            "setProgramState": "#/components/schemas/ControllerCommandRequestSetProgramStateCommandRequest",
            "setMasterValveState": "#/components/schemas/ControllerCommandRequestSetMasterValveStateCommandRequest",
            "setFilterValveState": "#/components/schemas/ControllerCommandRequestSetFilterValveStateCommandRequest",
            "resetControllerErrors": "#/components/schemas/ControllerCommandRequestResetControllerErrorsCommandRequest",
            "resetValveError": "#/components/schemas/ControllerCommandRequestResetValveErrorCommandRequest",
            "restartController": "#/components/schemas/ControllerCommandRequestRestartControllerCommandRequest",
            "restartSystems": "#/components/schemas/ControllerCommandRequestRestartSystemsCommandRequest",
            "resetAccumulator": "#/components/schemas/ControllerCommandRequestResetAccumulatorCommandRequest",
            "adjustRemainingState": "#/components/schemas/ControllerCommandRequestAdjustRemainingStateCommandRequest",
            "setOperatingMode": "#/components/schemas/ControllerCommandRequestSetOperatingModeCommandRequest"
          }
        }
      },
      "ControllerCommandRequestAdjustRemainingStateCommandRequest": {
        "required": [
          "target",
          "value"
        ],
        "properties": {
          "type": {
            "enum": [
              "adjustRemainingState"
            ],
            "type": "string"
          },
          "target": {
            "description": "Which countdown: `valveAmount`, `valveFertilizerAmount`, `valvePulseCount`,\n`valvePulseInterval`, `minutesBetweenIrrigationCycles` or `rinseTime`.",
            "$ref": "#/components/schemas/ControllerRemainingStateTarget"
          },
          "value": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The new value in the register's own unit, 0 to 65535; zero clears the countdown.",
            "format": "int32"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16; required for the four per-valve targets and ignored otherwise.",
            "format": "int32"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Overwrites one of an irrigation controller's running countdowns — what a \"clear remaining\nquantity\" control does. Requires `administer`."
      },
      "ControllerCommandRequestCloseValveManuallyCommandRequest": {
        "required": [
          "valveNumber"
        ],
        "properties": {
          "type": {
            "enum": [
              "closeValveManually"
            ],
            "type": "string"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16.",
            "format": "int32"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Closes a hand-opened valve, and the master valve with it when this was the last valve\nstill open. Requires `operate`. Answers 204 when the valve is not open by hand."
      },
      "ControllerCommandRequestOpenValveManuallyCommandRequest": {
        "required": [
          "valveNumber"
        ],
        "properties": {
          "type": {
            "enum": [
              "openValveManually"
            ],
            "type": "string"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16.",
            "format": "int32"
          },
          "includeMasterValve": {
            "type": "boolean",
            "description": "Also opens the master valve when the controller has one — the default, and the\ndifference between water reaching the valve and not.",
            "default": true
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Opens a valve by hand, outside any program. Requires `operate`. Answers 204 when the\nvalve is already open by hand."
      },
      "ControllerCommandRequestResetAccumulatorCommandRequest": {
        "required": [
          "target"
        ],
        "properties": {
          "type": {
            "enum": [
              "resetAccumulator"
            ],
            "type": "string"
          },
          "target": {
            "description": "Which total: `controllerIrrigation`, `controllerWaterLeak`,\n`controllerFertilizerLeak`, `controllerRinses`, `valveIrrigation` or\n`valveFertilizer`.",
            "$ref": "#/components/schemas/ControllerAccumulatorTarget"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16; required for the two per-valve targets and ignored otherwise.",
            "format": "int32"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Zeroes one of an irrigation controller's accumulating totals. Requires\n`resetAccumulators`."
      },
      "ControllerCommandRequestResetControllerErrorsCommandRequest": {
        "properties": {
          "type": {
            "enum": [
              "resetControllerErrors"
            ],
            "type": "string"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Clears the controller's error state — the irrigation controller's error latch, or the\nmaster controller's flow alarms. Requires `operate`."
      },
      "ControllerCommandRequestResetValveErrorCommandRequest": {
        "required": [
          "valveNumber"
        ],
        "properties": {
          "type": {
            "enum": [
              "resetValveError"
            ],
            "type": "string"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16.",
            "format": "int32"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Clears one valve's error state on an irrigation controller. Requires `operate`."
      },
      "ControllerCommandRequestRestartControllerCommandRequest": {
        "properties": {
          "type": {
            "enum": [
              "restartController"
            ],
            "type": "string"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Restarts an irrigation controller. Requires `administer`."
      },
      "ControllerCommandRequestRestartSystemsCommandRequest": {
        "properties": {
          "type": {
            "enum": [
              "restartSystems"
            ],
            "type": "string"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Restarts an irrigation controller's systems without restarting the controller. Requires `administer`."
      },
      "ControllerCommandRequestSetControllerEnabledCommandRequest": {
        "required": [
          "enabled"
        ],
        "properties": {
          "type": {
            "enum": [
              "setControllerEnabled"
            ],
            "type": "string"
          },
          "enabled": {
            "type": "boolean",
            "description": "True to return the controller to service, false to take it out."
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Puts an irrigation controller in or out of service. Requires the `administer`\ncapability. Answers 204 when the controller is already in the requested state."
      },
      "ControllerCommandRequestSetFilterValveStateCommandRequest": {
        "required": [
          "open"
        ],
        "properties": {
          "type": {
            "enum": [
              "setFilterValveState"
            ],
            "type": "string"
          },
          "open": {
            "type": "boolean",
            "description": "True to open, false to close."
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Opens or closes the irrigation controller's filter valve. Requires `operate`."
      },
      "ControllerCommandRequestSetMasterValveStateCommandRequest": {
        "required": [
          "open"
        ],
        "properties": {
          "type": {
            "enum": [
              "setMasterValveState"
            ],
            "type": "string"
          },
          "open": {
            "type": "boolean",
            "description": "True to open, false to close."
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Opens or closes the master valve. Supported on the irrigation controller, where the\nmaster valve occupies the last hardware port, and on the master controller, which has a\ndedicated address for it. Requires `operate`. On the irrigation controller, answers\n204 when the master valve is already in the requested state."
      },
      "ControllerCommandRequestSetOperatingModeCommandRequest": {
        "required": [
          "mode"
        ],
        "properties": {
          "type": {
            "enum": [
              "setOperatingMode"
            ],
            "type": "string"
          },
          "mode": {
            "description": "The mode to enter.",
            "$ref": "#/components/schemas/ControllerOperatingMode"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Sets the master controller's working mode: `active`, `inactiveOpen` (neutralized\nwith the master valve open) or `inactiveClosed`. Requires `operate`."
      },
      "ControllerCommandRequestSetProgramStateCommandRequest": {
        "required": [
          "programNumber",
          "running"
        ],
        "properties": {
          "type": {
            "enum": [
              "setProgramState"
            ],
            "type": "string"
          },
          "programNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based number of the program's first valve, 1 to 16.",
            "format": "int32"
          },
          "running": {
            "type": "boolean",
            "description": "True to start the program, false to stop it."
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Starts or stops a program by its first valve's number. Starting requires\n`startProgrammedIrrigation`; stopping requires `operate`."
      },
      "ControllerCommandRequestStartValveCommandRequest": {
        "required": [
          "valveNumber",
          "program"
        ],
        "properties": {
          "type": {
            "enum": [
              "startValve"
            ],
            "type": "string"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16, within what the controller has configured.",
            "format": "int32"
          },
          "program": {
            "description": "Which of the device's four start programs to run: `full` (with fertilizer, chained\ninto the following valves), `fertilizedUnchained`, `chainedWithoutFertilizer` or\n`plainUnchained`. The fertilizedUnchained option requires a fitted fertilizer valve;\nwithout one the command answers controllers.command_equipment_not_fitted. The full\noption uses the controller's configured program.",
            "$ref": "#/components/schemas/ControllerValveProgram"
          },
          "durationMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Optional bound on the run, 1 to 65535, written after the start so it bounds this run and\nnot the previous one, in the valve's own unit: minutes (or seconds, where the controller\ncounts time in seconds) on a valve that meters by time, whole cubic metres on one that\nmeters by volume — the same number the reference product's open-valve takes, scaled the\nsame way. Omit it to leave the valve's configured amount alone.",
            "format": "int32"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Starts a valve's programmed irrigation on an irrigation controller. Requires the\n`startProgrammedIrrigation` capability."
      },
      "ControllerCommandRequestStopValveCommandRequest": {
        "required": [
          "valveNumber"
        ],
        "properties": {
          "type": {
            "enum": [
              "stopValve"
            ],
            "type": "string"
          },
          "valveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based valve number, 1 to 16.",
            "format": "int32"
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Send the command in another project this user is authorized to work in — a customerId\nfrom GET /api/v1/auth/projects. Omit it to use the project the access token was issued\nfor. A project the user does not hold is refused with controllers.project_forbidden.",
            "format": "int64",
            "example": 88
          }
        },
        "additionalProperties": false,
        "description": "Stops a valve's programmed irrigation. Requires `operate`. Answers 204 when the\nvalve is already closed."
      },
      "ControllerCommandType": {
        "enum": [
          "setControllerEnabled",
          "startValve",
          "stopValve",
          "openValveManually",
          "closeValveManually",
          "setProgramState",
          "setMasterValveState",
          "setFilterValveState",
          "resetControllerErrors",
          "resetValveError",
          "restartController",
          "restartSystems",
          "resetAccumulator",
          "adjustRemainingState",
          "setOperatingMode"
        ],
        "description": "The closed set of command types the API accepts — one member per request type, named\nso that its camelCase spelling is the request's `type` discriminator. That is what\nlets the response echo the type as this enum and a client compare it with what it sent;\n`ControllerCommandTypes` pins the two spellings together."
      },
      "ControllerCommandWriteResponse": {
        "required": [
          "eventNumber",
          "value"
        ],
        "type": "object",
        "properties": {
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The event number written — the same number the realtime hub and the event catalogue use\nfor that register, so a client can match the device's echo to what was sent.",
            "format": "int32"
          },
          "value": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The value written, as the register takes it.",
            "format": "int32"
          }
        },
        "description": "One register write the delivery service was handed."
      },
      "ControllerConnectionsResponse": {
        "type": "object",
        "properties": {
          "tmsHub": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the traffic-management hub sharing this cabinet, as the RECO database\nrecords it. A cabinet detail, not a register."
          },
          "cctv": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the cameras sharing this cabinet. Database detail."
          }
        },
        "additionalProperties": false
      },
      "ControllerDamReading": {
        "type": "object",
        "properties": {
          "isolationFault": {
            "type": "boolean",
            "description": "Isolation fault on the cabinet supply (register 0 bit 2)."
          },
          "chargeRelayFault": {
            "type": "boolean",
            "description": "Battery charge relay fault (register 0 bit 3)."
          },
          "dcConverterFault": {
            "type": "boolean",
            "description": "DC converter fault (register 0 bit 4)."
          },
          "generalAlarm": {
            "type": "boolean",
            "description": "The general-alarm status bit (register 0 bit 14), at the same bit as on the\nlighting and irrigation controllers."
          },
          "communicationFault": {
            "type": "boolean",
            "description": "Communication fault with the cabinet (register 0 bit 15)."
          },
          "isCommunicationPowerDetected": {
            "type": "boolean",
            "description": "The communication controller reports mains power present (register 36 bit 1)."
          },
          "isCommunicationBatteryVoltageOk": {
            "type": "boolean",
            "description": "The communication controller reports its battery voltage in range (register 36\nbit 3)."
          },
          "clearAlarmsCommand": {
            "type": "boolean",
            "description": "State of the clear-alarms command latch; RECOM never sets it."
          },
          "configuredDamCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Dam count the controller is configured for. `dams` always carries the\nfour the register map covers: trimming to this value would hide a dam reporting\nstate after someone lowered the configured count, which is a fault worth seeing.",
            "format": "int32"
          },
          "communicationFlag": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Vendor communication flag, reported raw.",
            "format": "int32"
          },
          "totalAccumulation": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The controller's accumulating total (register 846), in the device's own\naccumulator units — no source confirms a scale, so the value stays raw rather\nthan guess one.",
            "format": "int32"
          },
          "dams": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerDamState"
            },
            "description": "The four dams, in controller order."
          }
        },
        "description": "`DM`-only subsystem detail: cabinet faults, the communication controller, and the\nfour dam gates. Null for every other model and for the short layout.",
        "x-controller-values": {
          "isolationFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 2",
            "events": [
              703,
              803
            ],
            "evidence": "dm.cabinet"
          },
          "chargeRelayFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 3",
            "events": [
              704,
              804
            ],
            "evidence": "dm.cabinet"
          },
          "dcConverterFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 4",
            "events": [
              705,
              805
            ],
            "evidence": "dm.cabinet"
          },
          "generalAlarm": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 14",
            "events": [
              715,
              815
            ],
            "evidence": "dm.cabinet"
          },
          "communicationFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 15",
            "events": [
              716,
              816
            ],
            "evidence": "dm.cabinet"
          },
          "isCommunicationPowerDetected": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 36 bit 1",
            "events": [
              3102,
              3202
            ],
            "evidence": "dm.cabinet"
          },
          "isCommunicationBatteryVoltageOk": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 36 bit 3",
            "events": [
              3104,
              3204
            ],
            "evidence": "dm.cabinet"
          },
          "clearAlarmsCommand": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 42 bit 0",
            "events": [
              1501,
              1601
            ],
            "evidence": "dm.dams"
          },
          "configuredDamCount": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 451",
            "events": [
              1802
            ],
            "evidence": "dm.scalars"
          },
          "communicationFlag": {
            "kind": "number",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 450",
            "events": [
              1801
            ],
            "evidence": "dm.scalars"
          },
          "totalAccumulation": {
            "kind": "number",
            "origin": "register",
            "unit": "unconfirmed",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 846",
            "events": [
              1901
            ],
            "evidence": "dm.scalars"
          },
          "dams": {
            "kind": "collection",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM status registers 1-4 and control registers 43-46",
            "events": [ ],
            "evidence": "dm.dams"
          }
        }
      },
      "ControllerDamState": {
        "type": "object",
        "properties": {
          "number": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based dam number, as the controller labels it.",
            "format": "int32"
          },
          "isOpen": {
            "type": "boolean",
            "description": "The dam is fully open (status register bit 0)."
          },
          "isClosed": {
            "type": "boolean",
            "description": "The dam is fully closed (status register bit 1)."
          },
          "isMoving": {
            "type": "boolean",
            "description": "The dam is travelling between its end positions (status register bit 2)."
          },
          "isOk": {
            "type": "boolean",
            "description": "The dam reports no fault (status register bit 3)."
          },
          "hasFeedbackFault": {
            "type": "boolean",
            "description": "The dam's position feedback disagrees with its drive (status register bit 15)."
          },
          "isControlEnabled": {
            "type": "boolean",
            "description": "True when the dam accepts remote open/close commands."
          },
          "openCommand": {
            "type": "boolean",
            "description": "State of the open command latch. RECOM issues no controller commands; this reports\nwhat the controller currently holds, whoever set it."
          },
          "closeCommand": {
            "type": "boolean",
            "description": "State of the close command latch; see `openCommand`."
          }
        },
        "description": "One dam of a `DM` controller: where its gate is, whether the feedback agrees, and\nwhether remote control over it is enabled.",
        "x-controller-values": {
          "number": {
            "kind": "number",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "one-based slot number",
            "source": "DM dam register slot",
            "events": [ ],
            "evidence": "dm.dams"
          },
          "isOpen": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam status registers 1-4 bit 0",
            "events": [
              717,
              733,
              749,
              765,
              817,
              833,
              849,
              865
            ],
            "evidence": "dm.dams"
          },
          "isClosed": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam status registers 1-4 bit 1",
            "events": [
              718,
              734,
              750,
              766,
              818,
              834,
              850,
              866
            ],
            "evidence": "dm.dams"
          },
          "isMoving": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam status registers 1-4 bit 2",
            "events": [
              719,
              735,
              751,
              767,
              819,
              835,
              851,
              867
            ],
            "evidence": "dm.dams"
          },
          "isOk": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam status registers 1-4 bit 3",
            "events": [
              720,
              736,
              752,
              768,
              820,
              836,
              852,
              868
            ],
            "evidence": "dm.dams"
          },
          "hasFeedbackFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam status registers 1-4 bit 15",
            "events": [
              732,
              748,
              764,
              780,
              832,
              848,
              864,
              880
            ],
            "evidence": "dm.dams"
          },
          "isControlEnabled": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam control registers 43-46 bit 0",
            "events": [
              1517,
              1533,
              1549,
              1565,
              1617,
              1633,
              1649,
              1665
            ],
            "evidence": "dm.dams"
          },
          "openCommand": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam control registers 43-46 bit 1",
            "events": [
              1518,
              1534,
              1550,
              1566,
              1618,
              1634,
              1650,
              1666
            ],
            "evidence": "dm.dams"
          },
          "closeCommand": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM dam control registers 43-46 bit 2",
            "events": [
              1519,
              1535,
              1551,
              1567,
              1619,
              1635,
              1651,
              1667
            ],
            "evidence": "dm.dams"
          }
        }
      },
      "ControllerDetailsAreaResponse": {
        "type": "object",
        "properties": {
          "zoneId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "zoneName": {
            "type": [
              "null",
              "string"
            ]
          },
          "regionId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "regionName": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "additionalProperties": false,
        "description": "The zone/region assignment RECO back office keeps for the controller."
      },
      "ControllerDetailsCommunicationResponse": {
        "type": "object",
        "properties": {
          "cellProvider": {
            "type": [
              "null",
              "string"
            ]
          },
          "simNumber": {
            "type": [
              "null",
              "string"
            ]
          },
          "phoneNumber": {
            "type": [
              "null",
              "string"
            ]
          },
          "lastCommunicationAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "SIM, cell carrier, and last-contact data for the controller's link."
      },
      "ControllerDetailsContractorResponse": {
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "additionalProperties": false,
        "description": "The maintenance contractor assigned to the controller."
      },
      "ControllerDetailsCustomerResponse": {
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "agreementStatus": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The customer's service-agreement status, with its vocabulary name.",
                "$ref": "#/components/schemas/ControllerCodedState"
              }
            ]
          }
        },
        "additionalProperties": false,
        "description": "The customer record the controller is registered under. ControllerCodedState? ControllerDetailsCustomerResponse.AgreementStatus is\na raw code; label decoding is client-owned."
      },
      "ControllerDetailsHardwareResponse": {
        "type": "object",
        "properties": {
          "controllerType": {
            "type": [
              "null",
              "string"
            ]
          },
          "controllerVersion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "modemType": {
            "type": [
              "null",
              "string"
            ]
          },
          "modemBoardType": {
            "type": [
              "null",
              "string"
            ]
          },
          "modemLast3G4G": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "commAdapterType": {
            "type": [
              "null",
              "string"
            ]
          },
          "commAdapterVersion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "powerSupplyCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int16"
          }
        },
        "additionalProperties": false,
        "description": "Controller, modem, and comm-adapter hardware identification. short? ControllerDetailsHardwareResponse.PowerSupplyCode\nis a raw code; label decoding is client-owned."
      },
      "ControllerDetailsInstallationResponse": {
        "type": "object",
        "properties": {
          "address": {
            "type": [
              "null",
              "string"
            ]
          },
          "installedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Where and when the controller was installed."
      },
      "ControllerDetailsLifecycleResponse": {
        "type": "object",
        "properties": {
          "lastChangedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "isDisabled": {
            "type": [
              "null",
              "boolean"
            ]
          }
        },
        "additionalProperties": false,
        "description": "The controller's last-change timestamp and enabled/disabled state."
      },
      "ControllerDetailsLightingResponse": {
        "type": "object",
        "properties": {
          "isControlled": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the cabinet is under remote control."
          },
          "isGeneratorPresent": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether a backup generator is installed."
          },
          "electricContractNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The supply contract the cabinet bills to.",
            "format": "int32"
          },
          "districtName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Administrative district the cabinet sits in."
          },
          "settlementName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Settlement the cabinet sits in."
          },
          "connections": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Equipment sharing the cabinet — traffic-management hub and cameras. Omitted when the\ncabinet records neither.",
                "$ref": "#/components/schemas/ControllerConnectionsResponse"
              }
            ]
          },
          "tollGates": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Toll gates fed from this cabinet. Omitted when it feeds none.",
                "$ref": "#/components/schemas/ControllerTollGatesResponse"
              }
            ]
          },
          "junctions": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Road junctions fed from this cabinet. Omitted when it feeds none.",
                "$ref": "#/components/schemas/ControllerJunctionsResponse"
              }
            ]
          }
        },
        "description": "The lighting cabinet's installation context, as the RECO back office records it: who\ncontrols it, what it bills to, where it stands, and what else it feeds."
      },
      "ControllerDetailsLocationResponse": {
        "type": "object",
        "properties": {
          "latitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "longitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "The controller's installed coordinates."
      },
      "ControllerDetailsNotesResponse": {
        "type": "object",
        "properties": {
          "objectNotes": {
            "type": [
              "null",
              "string"
            ]
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "deviceInfoNote": {
            "type": [
              "null",
              "string"
            ]
          },
          "deviceInfoAutoNote": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "additionalProperties": false,
        "description": "The four free-text note fields on the controller's detail record."
      },
      "ControllerDetailsPersonnelResponse": {
        "type": "object",
        "properties": {
          "waterTechnicianName": {
            "type": [
              "null",
              "string"
            ]
          },
          "supervisorName": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "additionalProperties": false,
        "description": "Named RECO back-office personnel assigned to the controller. Naming is owner-directed:\nstring? ControllerDetailsPersonnelResponse.WaterTechnicianName is the water technician, string? ControllerDetailsPersonnelResponse.SupervisorName is\nthe zones supervisor."
      },
      "ControllerDeviceStateResponse": {
        "required": [
          "modelType"
        ],
        "type": "object",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ControllerDeviceStateResponseLightingControllerDeviceStateResponse"
          },
          {
            "$ref": "#/components/schemas/ControllerDeviceStateResponseDamControllerDeviceStateResponse"
          },
          {
            "$ref": "#/components/schemas/ControllerDeviceStateResponseIrrigationControllerDeviceStateResponse"
          },
          {
            "$ref": "#/components/schemas/ControllerDeviceStateResponseIrrigationMasterControllerDeviceStateResponse"
          },
          {
            "$ref": "#/components/schemas/ControllerDeviceStateResponseWeatherStationControllerDeviceStateResponse"
          },
          {
            "$ref": "#/components/schemas/ControllerDeviceStateResponseUnknownControllerDeviceStateResponse"
          }
        ],
        "additionalProperties": false,
        "discriminator": {
          "propertyName": "modelType",
          "mapping": {
            "lighting": "#/components/schemas/ControllerDeviceStateResponseLightingControllerDeviceStateResponse",
            "dam": "#/components/schemas/ControllerDeviceStateResponseDamControllerDeviceStateResponse",
            "irrigation": "#/components/schemas/ControllerDeviceStateResponseIrrigationControllerDeviceStateResponse",
            "irrigationMaster": "#/components/schemas/ControllerDeviceStateResponseIrrigationMasterControllerDeviceStateResponse",
            "weatherStation": "#/components/schemas/ControllerDeviceStateResponseWeatherStationControllerDeviceStateResponse",
            "unknown": "#/components/schemas/ControllerDeviceStateResponseUnknownControllerDeviceStateResponse"
          }
        }
      },
      "ControllerDeviceStateResponseDamControllerDeviceStateResponse": {
        "properties": {
          "modelType": {
            "enum": [
              "dam"
            ],
            "type": "string"
          },
          "isPowerConnected": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether mains power is present at the dam cabinet (register 0 bit 0)."
          },
          "isDoorClosed": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the dam cabinet door is closed (register 0 bit 1)."
          },
          "batteryVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Controller battery voltage in volts (register 28 on the 548-register layout, 54 on\nthe 1066-register one; the register holds tenths of a volt).",
            "format": "double"
          },
          "isSystemDisabled": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the controller is disabled (register 0 bit 12; device event 713 reports it\nturning on and 813 turning off). Named for the fact the bit carries, not its\ncomplement, so a wrong reading fails rather than looking healthy."
          },
          "damControl": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The dam subsystem: cabinet faults, the communication controller, and the four dam\ngates with their position and control state.",
                "$ref": "#/components/schemas/ControllerDamReading"
              }
            ]
          },
          "syncedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the controller last synchronized this state. Null when no snapshot was\navailable, which is also when every value above it is null.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "x-controller-values": {
          "modelType": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "fixed JSON discriminator token",
            "source": "controller model response discriminator",
            "events": [ ],
            "evidence": "contract.model-type"
          },
          "isPowerConnected": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 0",
            "events": [
              701,
              801
            ],
            "evidence": "dm.cabinet"
          },
          "isDoorClosed": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 1",
            "events": [
              702,
              802
            ],
            "evidence": "dm.cabinet"
          },
          "batteryVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "DM long register 54",
            "events": [ ],
            "evidence": "dm.cabinet"
          },
          "isSystemDisabled": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM register 0 bit 12",
            "events": [
              713,
              813
            ],
            "evidence": "dm.cabinet"
          },
          "damControl": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "DM-only decoded subsystem",
            "events": [ ],
            "evidence": "dm.dams"
          },
          "syncedAtUtc": {
            "kind": "timestamp",
            "origin": "snapshotMetadata",
            "unit": "none",
            "unitSource": "",
            "encoding": "ISO-8601 UTC",
            "source": "snapshot synchronization timestamp",
            "events": [ ],
            "evidence": "contract.snapshot-metadata"
          }
        }
      },
      "ControllerDeviceStateResponseIrrigationControllerDeviceStateResponse": {
        "properties": {
          "modelType": {
            "enum": [
              "irrigation"
            ],
            "type": "string"
          },
          "batteryVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Controller battery voltage in volts (register 28 on the 548-register layout, 54 on\nthe 1066-register one; the register holds tenths of a volt).",
            "format": "double"
          },
          "alarmActive": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the controller raises its general alarm (register 14)."
          },
          "activeValvesCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "How many valves the controller runs (register 389 short, 760 long; device event\n2514). Valves past this count still hold register values but are not run.",
            "format": "int32"
          },
          "literPerPulse": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Litres one water-meter pulse represents (register 378 short, 749 long; device\nevent 2503, \"Liter To Water Meter Pulse Ratio\").",
            "format": "int32"
          },
          "version": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The board revision (register 38 on the 548-register layout, 64 on the 1066-register\none; device event 1711, which the reference names \"hardware version\"). Published with\nits kind, which is `hardware` here: a value above a threshold selects a different\nboard layout, and that is how the filter valve's port is decided.",
                "$ref": "#/components/schemas/ControllerVersion"
              }
            ]
          },
          "isSystemDisabled": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the controller is disabled (register 0 bit 12; device event 713 reports it\nturning on and 813 turning off). Named for the fact the bit carries, not its\ncomplement, so a wrong reading fails rather than looking healthy."
          },
          "irrigation": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The irrigation subsystem: clock, fitted hardware, filter rinsing, valves and the\nprograms reconstructed from them. Valves and programs come from the 548-register\nlayout only, the one that stores the per-valve configuration.",
                "$ref": "#/components/schemas/ControllerIrrigationReading"
              }
            ]
          },
          "syncedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the controller last synchronized this state. Null when no snapshot was\navailable, which is also when every value above it is null.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "x-controller-values": {
          "modelType": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "fixed JSON discriminator token",
            "source": "controller model response discriminator",
            "events": [ ],
            "evidence": "contract.model-type"
          },
          "batteryVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "I1 short register 28; long register 54",
            "events": [ ],
            "evidence": "i1.summary"
          },
          "alarmActive": {
            "kind": "boolean",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "short: raw != 0; long: raw == 0",
            "source": "I1 register 14",
            "events": [ ],
            "evidence": "i1.summary"
          },
          "activeValvesCount": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 389; long register 760",
            "events": [
              2514
            ],
            "evidence": "i1.summary"
          },
          "literPerPulse": {
            "kind": "number",
            "origin": "register",
            "unit": "litresPerPulse",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 378; long register 749",
            "events": [
              2503
            ],
            "evidence": "i1.summary"
          },
          "version": {
            "kind": "version",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw value plus hardware kind",
            "source": "I1 short register 38; long register 64",
            "events": [
              1711
            ],
            "evidence": "i1.summary"
          },
          "isSystemDisabled": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 12",
            "events": [
              713,
              813
            ],
            "evidence": "i1.status-bitmaps"
          },
          "irrigation": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1-only decoded subsystem",
            "events": [ ],
            "evidence": "i1.summary"
          },
          "syncedAtUtc": {
            "kind": "timestamp",
            "origin": "snapshotMetadata",
            "unit": "none",
            "unitSource": "",
            "encoding": "ISO-8601 UTC",
            "source": "snapshot synchronization timestamp",
            "events": [ ],
            "evidence": "contract.snapshot-metadata"
          }
        }
      },
      "ControllerDeviceStateResponseIrrigationMasterControllerDeviceStateResponse": {
        "properties": {
          "modelType": {
            "enum": [
              "irrigationMaster"
            ],
            "type": "string"
          },
          "batteryVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Controller battery voltage in volts (register 28 on the 548-register layout, 54 on\nthe 1066-register one; the register holds tenths of a volt).",
            "format": "double"
          },
          "currentFlow": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Flow through the master in m3/h (register 57, hundredths).",
            "format": "double"
          },
          "totalSlavesFlow": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Combined flow the slave controllers are drawing, in m3/h (register 58,\nhundredths).",
            "format": "double"
          },
          "version": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The controller's version register (59; device event 1706). Its kind is\n`unspecified`: unlike the irrigation controller, this model's sources name no\nhardware or software distinction, so none is invented here.",
                "$ref": "#/components/schemas/ControllerVersion"
              }
            ]
          },
          "irrigationMaster": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The master subsystem: fitted hardware, leak and uncontrolled-flow detection,\nsolenoid drive, and which slaves draw through each shared resource.",
                "$ref": "#/components/schemas/ControllerIrrigationMasterReading"
              }
            ]
          },
          "syncedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the controller last synchronized this state. Null when no snapshot was\navailable, which is also when every value above it is null.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "x-controller-values": {
          "modelType": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "fixed JSON discriminator token",
            "source": "controller model response discriminator",
            "events": [ ],
            "evidence": "contract.model-type"
          },
          "batteryVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "IP short register 28; long register 54",
            "events": [ ],
            "evidence": "ip.summary"
          },
          "currentFlow": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "raw / 100",
            "source": "IP long register 57",
            "events": [ ],
            "evidence": "ip.summary"
          },
          "totalSlavesFlow": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "raw / 100",
            "source": "IP long register 58",
            "events": [ ],
            "evidence": "ip.summary"
          },
          "version": {
            "kind": "version",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw value plus unspecified kind",
            "source": "IP long register 59",
            "events": [
              1706
            ],
            "evidence": "ip.summary"
          },
          "irrigationMaster": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP-only decoded subsystem",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "syncedAtUtc": {
            "kind": "timestamp",
            "origin": "snapshotMetadata",
            "unit": "none",
            "unitSource": "",
            "encoding": "ISO-8601 UTC",
            "source": "snapshot synchronization timestamp",
            "events": [ ],
            "evidence": "contract.snapshot-metadata"
          }
        }
      },
      "ControllerDeviceStateResponseLightingControllerDeviceStateResponse": {
        "properties": {
          "modelType": {
            "enum": [
              "lighting"
            ],
            "type": "string"
          },
          "isPowerConnected": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether mains power is present (register 0 bit 0)."
          },
          "isDoorClosed": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the cabinet door is closed (register 0 bit 1)."
          },
          "isSystemDisabled": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the controller is disabled (register 0 bit 12; device event 713 reports it\nturning on and 813 turning off). Named for the fact the bit carries, not its\ncomplement, so a wrong reading fails rather than looking healthy."
          },
          "isLightOn": {
            "type": [
              "null",
              "boolean"
            ],
            "description": "Whether the lighting is energised (register 1 bit 13)."
          },
          "currentTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "The controller's own clock as `HH:mm` (register 54, packed as the decimal\ndigits `HHmm` and rendered here)."
          },
          "sunriseTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Computed sunrise for today as `HH:mm` (register 55, packed `HHmm`)."
          },
          "sunsetTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Computed sunset for today as `HH:mm` (register 56, packed `HHmm`)."
          },
          "lightOnTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the lighting is due to switch on, as `HH:mm` (register 58, packed\n`HHmm`) - sunset shifted by the schedule's onset."
          },
          "lightOffTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the lighting is due to switch off, as `HH:mm` (register 57, packed\n`HHmm`) - sunrise shifted by the schedule's offset."
          },
          "version": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The cabinet's version register (59; device event 1706, \"version number\" in the\nreference). Its kind is `unspecified`, as the reference reports it.",
                "$ref": "#/components/schemas/ControllerVersion"
              }
            ]
          },
          "lightingControl": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The lighting subsystem: circuits, main switch, generator, communication controller\nand the configured schedule. Null on the 548-register layout, which does not carry\nit.",
                "$ref": "#/components/schemas/ControllerLightingReading"
              }
            ]
          },
          "syncedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the controller last synchronized this state. Null when no snapshot was\navailable, which is also when every value above it is null.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "x-controller-values": {
          "modelType": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "fixed JSON discriminator token",
            "source": "controller model response discriminator",
            "events": [ ],
            "evidence": "contract.model-type"
          },
          "isPowerConnected": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 0 bit 0",
            "events": [
              701,
              801
            ],
            "evidence": "lt.cabinet-status"
          },
          "isDoorClosed": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 0 bit 1",
            "events": [
              702,
              802
            ],
            "evidence": "lt.cabinet-status"
          },
          "isSystemDisabled": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 0 bit 12",
            "events": [
              713,
              813
            ],
            "evidence": "lt.cabinet-status"
          },
          "isLightOn": {
            "kind": "boolean",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "logical OR of the three circuit-on bits",
            "source": "LT register 1 bits 13-15",
            "events": [
              730,
              830
            ],
            "evidence": "lt.cabinet-status"
          },
          "currentTime": {
            "kind": "clock",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "HHmm packed decimal rendered as HH:mm",
            "source": "LT register 54",
            "events": [
              1701
            ],
            "evidence": "lt.schedule"
          },
          "sunriseTime": {
            "kind": "clock",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "HHmm packed decimal rendered as HH:mm",
            "source": "LT register 55",
            "events": [
              1702
            ],
            "evidence": "lt.schedule"
          },
          "sunsetTime": {
            "kind": "clock",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "HHmm packed decimal rendered as HH:mm",
            "source": "LT register 56",
            "events": [
              1703
            ],
            "evidence": "lt.schedule"
          },
          "lightOnTime": {
            "kind": "clock",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "HHmm packed decimal rendered as HH:mm",
            "source": "LT register 58",
            "events": [
              1705
            ],
            "evidence": "lt.schedule"
          },
          "lightOffTime": {
            "kind": "clock",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "HHmm packed decimal rendered as HH:mm",
            "source": "LT register 57",
            "events": [
              1704
            ],
            "evidence": "lt.schedule"
          },
          "version": {
            "kind": "version",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw value plus unspecified kind",
            "source": "LT register 59",
            "events": [
              1706
            ],
            "evidence": "lt.schedule"
          },
          "lightingControl": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT-only decoded subsystem",
            "events": [ ],
            "evidence": "lt.subsystems"
          },
          "syncedAtUtc": {
            "kind": "timestamp",
            "origin": "snapshotMetadata",
            "unit": "none",
            "unitSource": "",
            "encoding": "ISO-8601 UTC",
            "source": "snapshot synchronization timestamp",
            "events": [ ],
            "evidence": "contract.snapshot-metadata"
          }
        }
      },
      "ControllerDeviceStateResponseUnknownControllerDeviceStateResponse": {
        "properties": {
          "modelType": {
            "enum": [
              "unknown"
            ],
            "type": "string"
          }
        },
        "additionalProperties": false,
        "x-controller-values": {
          "modelType": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "fixed JSON discriminator token",
            "source": "controller model response discriminator",
            "events": [ ],
            "evidence": "contract.model-type"
          }
        }
      },
      "ControllerDeviceStateResponseWeatherStationControllerDeviceStateResponse": {
        "properties": {
          "modelType": {
            "enum": [
              "weatherStation"
            ],
            "type": "string"
          },
          "barometer": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Barometric pressure in mmHg (register 57).",
            "format": "double"
          },
          "outsideTemperature": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Outside temperature in degrees Celsius (register 60).",
            "format": "double"
          },
          "windSpeed": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Wind speed in km/h (register 61).",
            "format": "double"
          },
          "windSpeed10MinuteAverage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Ten-minute average wind speed in km/h (register 62).",
            "format": "double"
          },
          "outsideHumidity": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Outside relative humidity in percent (register 79).",
            "format": "int32"
          },
          "rainRate": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Rain rate in mm/h (register 87).",
            "format": "double"
          },
          "dayRain": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Rain accumulated today in mm (register 92).",
            "format": "double"
          },
          "dayEvaporation": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Evapotranspiration accumulated today in mm (register 95).",
            "format": "double"
          },
          "consoleBatteryVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Console battery voltage in volts (register 122).",
            "format": "double"
          },
          "syncedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the controller last synchronized this state. Null when no snapshot was\navailable, which is also when every value above it is null.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "x-controller-values": {
          "modelType": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "fixed JSON discriminator token",
            "source": "controller model response discriminator",
            "events": [ ],
            "evidence": "contract.model-type"
          },
          "barometer": {
            "kind": "number",
            "origin": "register",
            "unit": "millimetresOfMercury",
            "unitSource": "",
            "encoding": "raw * 25.4 / 1000",
            "source": "WE register 57",
            "events": [
              1704
            ],
            "evidence": "we.measurements"
          },
          "outsideTemperature": {
            "kind": "number",
            "origin": "register",
            "unit": "degreesCelsius",
            "unitSource": "",
            "encoding": "(raw - 320) * 5 / 90",
            "source": "WE register 60",
            "events": [
              1707
            ],
            "evidence": "we.measurements"
          },
          "windSpeed": {
            "kind": "number",
            "origin": "register",
            "unit": "kilometresPerHour",
            "unitSource": "",
            "encoding": "raw * 1.609344",
            "source": "WE register 61",
            "events": [
              1708
            ],
            "evidence": "we.wind-speed"
          },
          "windSpeed10MinuteAverage": {
            "kind": "number",
            "origin": "register",
            "unit": "kilometresPerHour",
            "unitSource": "",
            "encoding": "raw * 0.1609344",
            "source": "WE register 62",
            "events": [
              1709
            ],
            "evidence": "we.wind-speed-average"
          },
          "outsideHumidity": {
            "kind": "number",
            "origin": "register",
            "unit": "percent",
            "unitSource": "",
            "encoding": "raw",
            "source": "WE register 79",
            "events": [
              1726
            ],
            "evidence": "we.measurements"
          },
          "rainRate": {
            "kind": "number",
            "origin": "register",
            "unit": "millimetresPerHour",
            "unitSource": "",
            "encoding": "raw * 0.254",
            "source": "WE register 87",
            "events": [
              1734
            ],
            "evidence": "we.measurements"
          },
          "dayRain": {
            "kind": "number",
            "origin": "register",
            "unit": "millimetres",
            "unitSource": "",
            "encoding": "raw * 0.254",
            "source": "WE register 92",
            "events": [
              1739
            ],
            "evidence": "we.measurements"
          },
          "dayEvaporation": {
            "kind": "number",
            "origin": "register",
            "unit": "millimetres",
            "unitSource": "",
            "encoding": "raw * 0.0254",
            "source": "WE register 95",
            "events": [
              1742
            ],
            "evidence": "we.measurements"
          },
          "consoleBatteryVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw * 300 / 512 / 100",
            "source": "WE register 122",
            "events": [
              1769
            ],
            "evidence": "we.console-battery"
          },
          "syncedAtUtc": {
            "kind": "timestamp",
            "origin": "snapshotMetadata",
            "unit": "none",
            "unitSource": "",
            "encoding": "ISO-8601 UTC",
            "source": "snapshot synchronization timestamp",
            "events": [ ],
            "evidence": "contract.snapshot-metadata"
          }
        }
      },
      "ControllerEventBatchResponse": {
        "required": [
          "schemaVersion",
          "windowId",
          "batchSequence",
          "publishedAtUtc",
          "controllers"
        ],
        "type": "object",
        "properties": {
          "schemaVersion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "windowId": {
            "type": "string",
            "format": "uuid"
          },
          "batchSequence": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "publishedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "controllers": {
            "type": "array",
            "items": {
              "required": [
                "id",
                "parameters",
                "events"
              ],
              "type": "object",
              "properties": {
                "id": {
                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                  "type": [
                    "integer",
                    "string"
                  ],
                  "format": "int64"
                },
                "modelCode": {
                  "type": [
                    "null",
                    "string"
                  ],
                  "description": "The authoritative model code, from SQL rather than from the payload."
                },
                "reportedAtUtc": {
                  "type": [
                    "null",
                    "string"
                  ],
                  "description": "The latest moment any of these events was reported for.",
                  "format": "date-time"
                },
                "globalState": {
                  "required": [
                    "code",
                    "name",
                    "isConnected"
                  ],
                  "type": "object",
                  "properties": {
                    "code": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "integer",
                        "string"
                      ],
                      "format": "int32"
                    },
                    "name": {
                      "type": "string"
                    },
                    "isConnected": {
                      "type": "boolean"
                    }
                  }
                },
                "registerState": {
                  "type": "object",
                  "properties": {
                    "batteryVoltage": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "activeValvesCount": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "null",
                        "integer",
                        "string"
                      ],
                      "description": "How many valves the controller runs (I1 event 2514), when the batch carried it.",
                      "format": "int32"
                    },
                    "literPerPulse": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "description": "Litres one water-meter pulse represents (I1 event 2503), when the batch carried it.",
                      "format": "double"
                    },
                    "currentTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "sunriseTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "sunsetTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightOnTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightOffTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    }
                  },
                  "description": "What a batch reported, placed where the state publishes it: the same member names, types\nand renderings as ControllerRegisterStateResponse, carrying only the\nregisters these events named."
                },
                "parameters": {
                  "type": "object",
                  "additionalProperties": {
                    "required": [
                      "eventId",
                      "eventNumber",
                      "valueKind"
                    ],
                    "type": "object",
                    "properties": {
                      "eventId": {
                        "type": "string"
                      },
                      "eventNumber": {
                        "pattern": "^-?(?:0|[1-9]\\d*)$",
                        "type": [
                          "integer",
                          "string"
                        ],
                        "format": "int32"
                      },
                      "valueKind": {
                        "enum": [
                          "boolean",
                          "number",
                          "signedNumber",
                          "encodedTime",
                          "minutesFromMidnight",
                          "monthDay",
                          "tenths"
                        ],
                        "description": "How a device event's raw integer value should be read. The wire always carries an\ninteger; this says what that integer means, so a consumer renders it correctly instead\nof guessing from the parameter name."
                      },
                      "digitalValue": {
                        "type": [
                          "null",
                          "boolean"
                        ]
                      },
                      "textValue": {
                        "type": [
                          "null",
                          "string"
                        ]
                      },
                      "integerValue": {
                        "pattern": "^-?(?:0|[1-9]\\d*)$",
                        "type": [
                          "null",
                          "integer",
                          "string"
                        ],
                        "format": "int32"
                      },
                      "rawValue": {
                        "type": [
                          "null",
                          "string"
                        ],
                        "description": "The `Val` field of the `device.change` payload, verbatim. Published so a\nrendered reading can always be traced back to what the shard actually sent; absent\nwhen the payload carried none."
                      }
                    },
                    "description": "One parameter's reported value inside\nIReadOnlyDictionary&lt;string, ControllerEventParameterValueResponse&gt; ControllerBatchControllerResponse.Parameters, with the event that reported\nit so a value can be traced back to its own line in the batch."
                  },
                  "description": "The catalogued parameters this batch reported, by reference parameter name. Empty\nwhen nothing it carried was catalogued, which is not the same as nothing happening."
                },
                "events": {
                  "type": "array",
                  "items": {
                    "required": [
                      "category"
                    ],
                    "type": "object",
                    "anyOf": [
                      {
                        "required": [
                          "stateCode",
                          "stateName",
                          "isConnected",
                          "eventId",
                          "eventNumber"
                        ],
                        "properties": {
                          "category": {
                            "enum": [
                              "system"
                            ],
                            "type": "string"
                          },
                          "stateCode": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "stateName": {
                            "type": "string"
                          },
                          "isConnected": {
                            "type": "boolean"
                          },
                          "eventId": {
                            "type": "string",
                            "description": "Deterministic identity from the source coordinates\n(`controllerId:envelopeIndex:envelopeSource:eventNumber:ordinal:ticks`), so a\nreplayed frame deduplicates."
                          },
                          "eventNumber": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "occurredAtUtc": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "envelopeIndex": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The frame counter the source put on the `device.change` envelope, verbatim. It\nincrements per controller, and one batch can carry events from consecutive envelopes,\nso it stays here rather than moving up to the controller.",
                            "format": "int32"
                          },
                          "envelopeSource": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The envelope's source field, verbatim and opaque — every observed frame carries 1.",
                            "format": "int32"
                          }
                        },
                        "description": "The global-state event (number 6): the controller's state code and connectivity."
                      },
                      {
                        "required": [
                          "parameterName",
                          "valueKind",
                          "eventId",
                          "eventNumber"
                        ],
                        "properties": {
                          "category": {
                            "enum": [
                              "parameter"
                            ],
                            "type": "string"
                          },
                          "parameterName": {
                            "type": "string",
                            "description": "Reference parameter name, carried verbatim so it matches the register state."
                          },
                          "valueKind": {
                            "enum": [
                              "boolean",
                              "number",
                              "signedNumber",
                              "encodedTime",
                              "minutesFromMidnight",
                              "monthDay",
                              "tenths"
                            ],
                            "description": "How a device event's raw integer value should be read. The wire always carries an\ninteger; this says what that integer means, so a consumer renders it correctly instead\nof guessing from the parameter name."
                          },
                          "digitalValue": {
                            "type": [
                              "null",
                              "boolean"
                            ],
                            "description": "Set for `Boolean` parameters."
                          },
                          "textValue": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "description": "The reading the kind implies: `HH:mm` for a clock, `dd-MM` for a packed\ncalendar day (the register packs day x 100 + month), a scaled decimal for tenths."
                          },
                          "integerValue": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The raw controller value, sign-corrected for signed parameters.",
                            "format": "int32"
                          },
                          "rawValue": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "description": "The payload's own `Val`, before any reading was made of it."
                          },
                          "eventId": {
                            "type": "string",
                            "description": "Deterministic identity from the source coordinates\n(`controllerId:envelopeIndex:envelopeSource:eventNumber:ordinal:ticks`), so a\nreplayed frame deduplicates."
                          },
                          "eventNumber": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "occurredAtUtc": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "envelopeIndex": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The frame counter the source put on the `device.change` envelope, verbatim. It\nincrements per controller, and one batch can carry events from consecutive envelopes,\nso it stays here rather than moving up to the controller.",
                            "format": "int32"
                          },
                          "envelopeSource": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The envelope's source field, verbatim and opaque — every observed frame carries 1.",
                            "format": "int32"
                          }
                        },
                        "description": "A device event the catalogue resolved: it says which parameter it reports and how its\nvalue should be read, instead of arriving as a bare number to interpret."
                      },
                      {
                        "required": [
                          "eventId",
                          "eventNumber"
                        ],
                        "properties": {
                          "category": {
                            "enum": [
                              "unclassified"
                            ],
                            "type": "string"
                          },
                          "textValue": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "numericValue": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "rawValue": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "description": "The payload's own `Val`, verbatim."
                          },
                          "eventId": {
                            "type": "string",
                            "description": "Deterministic identity from the source coordinates\n(`controllerId:envelopeIndex:envelopeSource:eventNumber:ordinal:ticks`), so a\nreplayed frame deduplicates."
                          },
                          "eventNumber": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "occurredAtUtc": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "envelopeIndex": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The frame counter the source put on the `device.change` envelope, verbatim. It\nincrements per controller, and one batch can carry events from consecutive envelopes,\nso it stays here rather than moving up to the controller.",
                            "format": "int32"
                          },
                          "envelopeSource": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The envelope's source field, verbatim and opaque — every observed frame carries 1.",
                            "format": "int32"
                          }
                        },
                        "description": "A device event the catalogue does not name: its number and value, and nothing claimed\nabout what it means. An honest gap beats a guess, and the number still says where it\ncame from."
                      },
                      {
                        "required": [
                          "isStart",
                          "eventId",
                          "eventNumber"
                        ],
                        "properties": {
                          "category": {
                            "enum": [
                              "elog"
                            ],
                            "type": "string"
                          },
                          "isStart": {
                            "type": "boolean"
                          },
                          "eventCode": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "eventDescription": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "actionInstructions": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "eventId": {
                            "type": "string",
                            "description": "Deterministic identity from the source coordinates\n(`controllerId:envelopeIndex:envelopeSource:eventNumber:ordinal:ticks`), so a\nreplayed frame deduplicates."
                          },
                          "eventNumber": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "occurredAtUtc": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "envelopeIndex": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The frame counter the source put on the `device.change` envelope, verbatim. It\nincrements per controller, and one batch can carry events from consecutive envelopes,\nso it stays here rather than moving up to the controller.",
                            "format": "int32"
                          },
                          "envelopeSource": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "null",
                              "integer",
                              "string"
                            ],
                            "description": "The envelope's source field, verbatim and opaque — every observed frame carries 1.",
                            "format": "int32"
                          }
                        },
                        "description": "An ELOG event. Reserved: ELOG ingestion is not implemented, so none arrive yet."
                      }
                    ],
                    "description": "One event inside a batch. The coordinates every event carries live here; each category\nadds only what it alone reports.",
                    "discriminator": {
                      "propertyName": "category",
                      "mapping": {
                        "system": "#/components/schemas/ControllerBatchEventResponseSystemBatchEventResponse",
                        "parameter": "#/components/schemas/ControllerBatchEventResponseParameterBatchEventResponse",
                        "unclassified": "#/components/schemas/ControllerBatchEventResponseUnclassifiedBatchEventResponse",
                        "elog": "#/components/schemas/ControllerBatchEventResponseElogBatchEventResponse"
                      }
                    }
                  },
                  "description": "The events themselves, in the order the frame carried them."
                }
              },
              "description": "Everything a batch has to say about one controller: the events it carried, and the state\nthey reported, in one object."
            },
            "description": "One entry per controller this batch has something to say about."
          }
        },
        "description": "One publication of device events, grouped by the controller they belong to."
      },
      "ControllerEventCadence": {
        "enum": [
          "onChange",
          "continuous"
        ],
        "description": "How often a catalogued event is expected to arrive: when something changes, or\ncontinuously because it mirrors a physical input the controller re-reads every second."
      },
      "ControllerEventLabel": {
        "required": [
          "hebrew",
          "english"
        ],
        "type": "object",
        "properties": {
          "hebrew": {
            "type": [
              "null",
              "string"
            ],
            "description": "The reference's Hebrew label, or `null` where it has none. Present for\nLT, DM, I1 and IP; absent throughout WE, whose labels are Latin in both source fields."
          },
          "english": {
            "type": [
              "null",
              "string"
            ],
            "description": "The reference's Latin label, or `null` where it has none. Present for\nI1, IP and WE; absent throughout LT and DM, which the reference labels in Hebrew only."
          }
        },
        "description": "The Agam reference's own display text for one event number on one model.\nThis is not a parameter name and must never be presented as one. The names in\nControllerEventCatalog were confirmed against the reference's register\nparsers; these strings are another product's UI labels, and the Latin ones are machine\ntranslations of the Hebrew (I1 714 reads \"The cave by irrigation or washing\").\nThey are carried so a client can show a human something for an event no catalogue names,\nclearly marked as unreviewed upstream text."
      },
      "ControllerEventSource": {
        "enum": [
          "deviceChange",
          "elog"
        ],
        "description": "Which stream an event came from. Crosses both the hub and REST as the name below."
      },
      "ControllerEventValueKind": {
        "enum": [
          "boolean",
          "number",
          "signedNumber",
          "encodedTime",
          "minutesFromMidnight",
          "monthDay",
          "tenths",
          null
        ]
      },
      "ControllerGeneratorState": {
        "type": "object",
        "properties": {
          "isOn": {
            "type": "boolean",
            "description": "The generator is running."
          },
          "hasError": {
            "type": "boolean",
            "description": "The generator reports a fault."
          },
          "isMinimumSwitchOn": {
            "type": "boolean",
            "description": "The generator's minimum-level switch is engaged."
          },
          "hasBatteryChargerError": {
            "type": "boolean",
            "description": "The generator's battery charger reports a fault."
          },
          "isFuelLevelLow": {
            "type": "boolean",
            "description": "Fuel level is below the configured threshold."
          }
        },
        "description": "Standby-generator status of an LT controller, decoded from the generator register.\nIt backs the essential lighting circuits when mains power fails, so its faults are\noperationally urgent even while the lights are still on.",
        "x-controller-values": {
          "isOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 bit 0",
            "events": [
              733,
              833
            ],
            "evidence": "lt.subsystems"
          },
          "hasError": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 bit 1",
            "events": [
              734,
              834
            ],
            "evidence": "lt.subsystems"
          },
          "isMinimumSwitchOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 bit 4",
            "events": [
              737,
              837
            ],
            "evidence": "lt.subsystems"
          },
          "hasBatteryChargerError": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 bit 5",
            "events": [
              738,
              838
            ],
            "evidence": "lt.subsystems"
          },
          "isFuelLevelLow": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 bit 6",
            "events": [
              739,
              839
            ],
            "evidence": "lt.subsystems"
          }
        }
      },
      "ControllerGlobalStateResponse": {
        "type": "object",
        "properties": {
          "code": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "isConnected": {
            "type": [
              "null",
              "boolean"
            ]
          }
        },
        "additionalProperties": false,
        "description": "The real-time global state: its raw code, fixed vocabulary name, and connectivity."
      },
      "ControllerIrrigationFilterWashBehaviour": {
        "enum": [
          "stopIrrigationAndFertilization",
          "continueIrrigationAndFertilization",
          "stopFertilizationOnly",
          "unused"
        ],
        "description": "What an I1 controller keeps running while its filter washes, read from bits 0 and 1 of\nthe behaviour register (18 short / 44 long; events 1533/1633 and 1534/1634 respectively)."
      },
      "ControllerIrrigationHighFlowBehaviour": {
        "enum": [
          "closeValveWithAutomaticReset",
          "closeAndDisableValveWithManualReset",
          "pauseProgramWithAutomaticReset",
          "pauseProgramDisableValveWithAutomaticProgramReset"
        ],
        "description": "What an I1 controller does when a running program reports a high flow, read from the two\nbits that decide it together: the behaviour register's bit 5 (18 short / 44 long, events\n1538/1638) chooses between closing the offending valve and pausing the whole program, and\nbit 2 of register 393 (764 long, event 2518) chooses between an automatic reset and one a\nperson has to perform."
      },
      "ControllerIrrigationMasterReading": {
        "required": [
          "status",
          "leakageControlMode"
        ],
        "type": "object",
        "properties": {
          "hasFlowmeter": {
            "type": "boolean",
            "description": "Whether a flowmeter is fitted (setup register 43 bit 0)."
          },
          "hasMainValve": {
            "type": "boolean",
            "description": "Whether a main valve is fitted (setup register 43 bit 1)."
          },
          "calculatesFlow": {
            "type": "boolean",
            "description": "Whether the master computes flow rather than only measuring it (setup register\n43 bit 2)."
          },
          "hasPump1": {
            "type": "boolean",
            "description": "Whether the first pump is fitted (setup register 43 bit 3)."
          },
          "hasPump2": {
            "type": "boolean",
            "description": "Whether the second pump is fitted (setup register 43 bit 5 — bit 4 belongs to\nneither pump, so the two are not adjacent)."
          },
          "isMasterValveOpen": {
            "type": "boolean",
            "description": "Whether the master valve is open (register 0 bit 0)."
          },
          "isMasterValveOpenedManually": {
            "type": "boolean",
            "description": "Whether the master valve was opened manually (register 0 bit 3)."
          },
          "hasFlowAlarmByMeasure": {
            "type": "boolean",
            "description": "Whether a flow alarm raised from measurement is active (register 0 bit 4)."
          },
          "hasFlowAlarmWithoutMeasure": {
            "type": "boolean",
            "description": "Whether a flow alarm raised without measurement is active (register 0 bit 5)."
          },
          "generalAlarm": {
            "type": "boolean",
            "description": "The general-alarm status bit (register 0 bit 7), as on LT, DM and I1."
          },
          "batteryStatusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Raw battery-status code (register 55). A plain code, not a\nControllerCodedState: no source confirms a vocabulary for it, and a\npermanently null name would be noise. Labels are client-owned, as with every other\npublished code.",
            "format": "int32"
          },
          "status": {
            "description": "The master's operating status (register 56) with the reference vocabulary's name:\n`active` (0), `inactiveOpened` (1), `inactiveClosed` (2).",
            "$ref": "#/components/schemas/ControllerCodedState"
          },
          "leakageControlMode": {
            "description": "What the master does when it detects a leak (register 451): `noControl` (0),\n`temporaryClose` (1), `permanentClose` (2).",
            "$ref": "#/components/schemas/ControllerCodedState"
          },
          "litresPerPulse": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Litres a flowmeter pulse represents. The register holds a decade code (1, 10, 100,\n1000) which is resolved here, so the value is litres and not a code to look up.\nNull when the register holds none of the four known codes.",
            "format": "int32"
          },
          "leakDetectionMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Leak-detection window in minutes (the reference register is named in minutes).",
            "format": "int32"
          },
          "leakDetectionPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How far past the expected flow counts as a leak, as a percentage (register 454).",
            "format": "int32"
          },
          "uncontrolledFlowDetectionTime": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Uncontrolled-flow detection window, in device time units no source names.",
            "format": "int32"
          },
          "uncontrolledFlowDetectionPulses": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many flowmeter pulses with no valve open raise uncontrolled flow\n(register 456).",
            "format": "int32"
          },
          "closeValveDelaySeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Seconds the master waits before rejecting a close (named in seconds by the reference).",
            "format": "int32"
          },
          "valveOpenVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Solenoid open drive voltage in volts (register 458, stored in tenths of a volt).\nSame fact and name as the irrigation controller's value.",
            "format": "double"
          },
          "valveOpenTimeMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Solenoid open drive time in milliseconds (named in ms by the reference).",
            "format": "int32"
          },
          "valveCloseVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Solenoid close drive voltage in volts (register 460, tenths of a volt).",
            "format": "double"
          },
          "valveCloseTimeMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Solenoid close drive time in milliseconds (named in ms by the reference).",
            "format": "int32"
          },
          "manualOpenMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How long a manual pump or valve activation runs, in minutes (register 462).",
            "format": "int32"
          },
          "mainValveSlaves": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Slave numbers (1-32) that irrigate through this master's main valve."
          },
          "pump1Slaves": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Slave numbers (1-32) that draw through the first pump — two registers from 604,\nlow word first. The device stores these inverted, so a clear bit means the\nslave uses the pump; the inversion is undone in the register map so no consumer\nrepeats it."
          },
          "pump2Slaves": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Slave numbers (1-32) that draw through the second pump — two registers from 606,\ninverted the same way."
          }
        },
        "description": "`IP`-only subsystem detail: which hardware the master has, how it handles leaks,\nhow its valves are driven, and which slaves share its main valve and pumps. Null for\nevery other model and for the short layout, which reports none of it.",
        "x-controller-values": {
          "hasFlowmeter": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 43 bit 0",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "hasMainValve": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 43 bit 1",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "calculatesFlow": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 43 bit 2",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "hasPump1": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 43 bit 3",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "hasPump2": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 43 bit 5",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "isMasterValveOpen": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 0 bit 0",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "isMasterValveOpenedManually": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 0 bit 3",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "hasFlowAlarmByMeasure": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 0 bit 4",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "hasFlowAlarmWithoutMeasure": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 0 bit 5",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "generalAlarm": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 0 bit 7",
            "events": [ ],
            "evidence": "ip.hardware-status"
          },
          "batteryStatusCode": {
            "kind": "number",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw code with unconfirmed vocabulary",
            "source": "IP register 55",
            "events": [ ],
            "evidence": "ip.coded-status"
          },
          "status": {
            "kind": "codedState",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "0=active; 1=inactiveOpened; 2=inactiveClosed",
            "source": "IP register 56",
            "events": [ ],
            "evidence": "ip.coded-status"
          },
          "leakageControlMode": {
            "kind": "codedState",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "0=noControl; 1=temporaryClose; 2=permanentClose",
            "source": "IP register 451",
            "events": [ ],
            "evidence": "ip.coded-status"
          },
          "litresPerPulse": {
            "kind": "number",
            "origin": "derived",
            "unit": "litresPerPulse",
            "unitSource": "",
            "encoding": "1->10; 10->100; 100->1000; 1000->10000; otherwise null",
            "source": "IP register 452",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "leakDetectionMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 453",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "leakDetectionPercent": {
            "kind": "number",
            "origin": "register",
            "unit": "percent",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 454",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "uncontrolledFlowDetectionTime": {
            "kind": "number",
            "origin": "register",
            "unit": "unconfirmed",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 455",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "uncontrolledFlowDetectionPulses": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 456",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "closeValveDelaySeconds": {
            "kind": "number",
            "origin": "register",
            "unit": "seconds",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 457",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "valveOpenVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "IP register 458",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "valveOpenTimeMs": {
            "kind": "number",
            "origin": "register",
            "unit": "milliseconds",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 459",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "valveCloseVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "IP register 460",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "valveCloseTimeMs": {
            "kind": "number",
            "origin": "register",
            "unit": "milliseconds",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 461",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "manualOpenMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "IP register 462",
            "events": [ ],
            "evidence": "ip.leak-valve-config"
          },
          "mainValveSlaves": {
            "kind": "collection",
            "origin": "registerPair",
            "unit": "none",
            "unitSource": "",
            "encoding": "inverted bitmap; clear bits become slave numbers 1-32",
            "source": "IP registers 602-603",
            "events": [ ],
            "evidence": "ip.shared-resources"
          },
          "pump1Slaves": {
            "kind": "collection",
            "origin": "registerPair",
            "unit": "none",
            "unitSource": "",
            "encoding": "inverted bitmap; clear bits become slave numbers 1-32",
            "source": "IP registers 604-605",
            "events": [ ],
            "evidence": "ip.shared-resources"
          },
          "pump2Slaves": {
            "kind": "collection",
            "origin": "registerPair",
            "unit": "none",
            "unitSource": "",
            "encoding": "inverted bitmap; clear bits become slave numbers 1-32",
            "source": "IP registers 606-607",
            "events": [ ],
            "evidence": "ip.shared-resources"
          }
        }
      },
      "ControllerIrrigationProgram": {
        "type": "object",
        "properties": {
          "number": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Sequence number in discovery order (by valve number), one-based.",
            "format": "int32"
          },
          "startTimeMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Start, in minutes from midnight.",
            "format": "int32"
          },
          "startTime": {
            "type": "string",
            "description": "The same start as a time of day, `HH:mm`, copied from the first valve's\n`startTime` so a program and the valve that starts it never disagree."
          },
          "startWeekDays": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerCodedState"
            },
            "description": "The weekdays the program starts on, as Sunday-first coded pairs (`1` =\n`sunday` … `7` = `saturday` — the day-of-week vocabulary)."
          },
          "fertilizationWeekDays": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerCodedState"
            },
            "description": "The weekdays the program fertilizes on, from the high byte of the same first-valve\nregister its start days come from; the same Sunday-first vocabulary."
          },
          "factorPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The irrigation-change percentage the program runs at, taken from its valves'\nown factor registers (459 plus the valve slot). Not a register of the program's\nown: a program is reconstructed from its valves, and every non-companion valve\nin one must agree on this number — a disagreement is reported as a\nconfiguration error rather than silently resolved.",
            "format": "int32"
          },
          "valveNumbers": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valve numbers in run order: each chained valve followed by the valves that open\nwith it."
          }
        },
        "description": "One irrigation program: a chain of valves that starts together, on the days and at the\ntime its first valve is configured for.",
        "x-controller-values": {
          "number": {
            "kind": "number",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "one-based discovery sequence",
            "source": "I1 reconstructed valve programs",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "startTimeMinutes": {
            "kind": "clock",
            "origin": "derived",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "minutes from midnight copied from first valve",
            "source": "I1 valve start-time register block",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "startTime": {
            "kind": "clock",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "startTimeMinutes rendered HH:mm, copied from first valve",
            "source": "I1 valve start-time register block",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "startWeekDays": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 0-6 of the first valve's weekly-schedule register become Sunday-first coded days",
            "source": "I1 first-valve weekly-schedule register",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "fertilizationWeekDays": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 8-14 of the first valve's weekly-schedule register become Sunday-first coded days",
            "source": "I1 first-valve weekly-schedule register",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "factorPercent": {
            "kind": "number",
            "origin": "derived",
            "unit": "percent",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 valve irrigation-factor register block",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "valveNumbers": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "start-after chain with start-with companions",
            "source": "I1 valve scheduling configuration",
            "events": [ ],
            "evidence": "i1.programs"
          }
        }
      },
      "ControllerIrrigationReading": {
        "required": [
          "dayOfWeek",
          "totalFertilizerLeak"
        ],
        "type": "object",
        "properties": {
          "clockMinutesFromMidnight": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Controller clock in minutes from midnight. Not the `HHmm` encoding the lighting\nclock uses: the irrigation register genuinely holds minutes, and normalising the two\ninto one field would make a wrong reading indistinguishable from a right one.",
            "format": "int32"
          },
          "dayOfWeek": {
            "description": "The controller's own day-of-week register — register 178 on the 548-register layout\nand 549 on the 1066-register one, directly below the clock; reported live as\nanalogue event 2301. The code is the raw register value; the confirmed vocabulary\nruns `1` = `sunday` through `7` = `saturday`, and a value\noutside it keeps a null name.\nThe controller keeps this calendar itself and can run offline or drift from server\ntime, so it is the device's own answer rather than a derivation of the server clock;\ncompare the two rather than assuming they agree.",
            "$ref": "#/components/schemas/ControllerCodedState"
          },
          "hasMainValve": {
            "type": "boolean",
            "description": "Whether a main valve is fitted: bit 0 of the setup register (17 on the\n548-register layout, 43 on the 1066-register one), which the reference names\n\"Master Valve Exists\". It is also what decides the main valve's port number,\nsince a fitted main valve occupies the last hardware port."
          },
          "hardwarePortCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many valve ports the controller board has (register 40 on the 548-register\nlayout, 66 on the 1066-register one; reported as analogue event 1713).\nThis is the fact that says which port number the special valves occupy: the\nmain valve is the last port when one is fitted, and the filter valve sits below it,\nbelow the fertilizer valve again when that is fitted too. A command addressed at the\nmain valve without it would either guess a port or refuse to run.",
            "format": "int32"
          },
          "hasFilter": {
            "type": "boolean",
            "description": "Whether a filter is fitted (register 42 short, 68 long; analogue event 1715). The\ndevice reports this as a whole register rather than a status bit, so any non-zero\nvalue means fitted."
          },
          "filterCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many filters the controller rinses (register 390 short, 761 long; event 2515).\nZero when `hasFilter` is false.",
            "format": "int32"
          },
          "hasFertilizerValve": {
            "type": "boolean",
            "description": "Whether a fertilizer valve is fitted: bit 1 of the setup register (17 short, 43\nlong), \"Compost Exists\" in the reference."
          },
          "supportsPulses": {
            "type": "boolean",
            "description": "Whether pulse irrigation is supported: bit 2 of the setup register (17 short, 43\nlong), \"Allow Pulse Watering\" in the reference."
          },
          "isFertilizerByTime": {
            "type": "boolean",
            "description": "Whether the controller doses fertilizer by time rather than by quantity (setup\nregister bit 6). It is what decides whether a valve's fertilizer accumulator counts\nhours or litres, so it is published as a fact of its own rather than only as the unit\nbeside that value."
          },
          "isFertilizerProportional": {
            "type": "boolean",
            "description": "Whether fertilizer is dosed in proportion to the water flowing (setup register bit 7)\nrather than as a fixed amount."
          },
          "isRinsingBlockedDuringPipeFill": {
            "type": "boolean",
            "description": "Whether the controller refuses to start a filter rinse while pipes are still filling\n(setup register bit 5)."
          },
          "isWaterMeterInputOn": {
            "type": "boolean",
            "description": "The water meter's input line as the controller last read it: register 2 bit 0,\nreported on by event 733 and off by 833. A live contact, not a presence flag — the\ncontroller re-reports it about once a second while water moves, which the legacy\nUI shows as a pulse indicator on the main valve. Whether a meter is fitted at all\nis `supportsPulses`. A state refresh holds the value at the snapshot; the hub\nwindow carries it as it moves."
          },
          "isFertilizerMeterInputOn": {
            "type": "boolean",
            "description": "The fertilizer meter's input line (register 2 bit 1; events 734/834). Live, as the water meter's is."
          },
          "isPressureMeterInputOn": {
            "type": "boolean",
            "description": "The pressure meter's input line (register 2 bit 2; events 735/835)."
          },
          "isPressureDifferentialMeterInputOn": {
            "type": "boolean",
            "description": "The differential-pressure meter's input line (register 2 bit 3; events 736/836)."
          },
          "controllerAddress": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The controller's own network address (read-only register 39 short, 65 long), the\nsame fact the catalogue already names `controllerAddress` at event 1712.",
            "format": "int32"
          },
          "irrigatingValveNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Number of the valve the controller reports as irrigating now (read-only register 37\nshort, 63 long; event 1710, \"the valve now irrigating\"). Both mapping files name it\n`RO_ActualIrrigationValve`; what the register holds while nothing irrigates is\nstated by no source, so the value is published raw rather than turned into a null.",
            "format": "int32"
          },
          "filterWashBehaviour": {
            "description": "What keeps running while the filter washes, from bits 0 and 1 of the behaviour\nregister (18 short / 44 long; events 1533/1633 and 1534/1634). The two bits select\none behaviour between them, so the contract publishes the behaviour rather than the\nbits — see ControllerIrrigationFilterWashBehaviour.",
            "$ref": "#/components/schemas/ControllerIrrigationFilterWashBehaviour"
          },
          "highFlowBehaviour": {
            "description": "What the controller does about a program reporting a high flow, from the behaviour\nregister's bit 5 (events 1538/1638) together with bit 2 of register 393 (764 long,\nevent 2518). Neither bit states a behaviour on its own — see\nControllerIrrigationHighFlowBehaviour.",
            "$ref": "#/components/schemas/ControllerIrrigationHighFlowBehaviour"
          },
          "continuesIrrigationOnFertilizerFault": {
            "type": "boolean",
            "description": "Whether irrigation carries on when the fertilizer system faults (behaviour register\n18 short / 44 long, bit 2; events 1535/1635)."
          },
          "opensMainValveBeforeValves": {
            "type": "boolean",
            "description": "Whether the main valve opens before the valves it feeds (behaviour register 18\nshort / 44 long, bit 3; events 1536/1636)."
          },
          "opensMainValveAfterValves": {
            "type": "boolean",
            "description": "Whether the main valve opens after the valves it feeds (behaviour register 18\nshort / 44 long, bit 4; events 1537/1637). The companion of\n`opensMainValveBeforeValves`: the device carries the two orderings as\nseparate bits, so they are published as the two facts it reports."
          },
          "allowsValveGrouping": {
            "type": "boolean",
            "description": "Whether a valve may open alongside other valves rather than only on its own\n(behaviour register 18 short / 44 long, bit 7; events 1540/1640)."
          },
          "isExternalPowerConnected": {
            "type": "boolean",
            "description": "Whether external power is connected (register 15 bit 1; events 1150/1250). The\nregister sits in the status zone, so the index is the same on both layouts."
          },
          "isCharging": {
            "type": "boolean",
            "description": "Whether the controller is charging (register 15 bit 4; events 1153/1253)."
          },
          "externalPowerVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "External power supply voltage (register 29 short, 55 long; event 1702), stored in\ntenths of a volt exactly as the battery voltage beside it is.",
            "format": "double"
          },
          "autoNominalFlowChangePercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Percentage change applied to the nominal flow in automatic mode (register 80 on\nthe short layout, 451 on the long one).",
            "format": "int32"
          },
          "mainValveDelaySeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Delay before the main valve acts, in seconds (register 377 short, 748 long).",
            "format": "int32"
          },
          "valveOpenVoltage": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Solenoid drive voltage in volts — the low byte of the packed valve-drive register\n(79, short layout only), stored in tenths of a volt. Null on the long layout, whose\nequivalent register is unconfirmed. Same fact and name as the IP master's value.",
            "format": "double"
          },
          "valveOpenTimeMs": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Solenoid drive time in milliseconds — the high byte of the same packed register.",
            "format": "int32"
          },
          "currentFlow": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Current water flow in m³/h — a 32-bit LSW/MSW register pair joined here and scaled\nby the reference's ÷100, so consumers never see the 16-bit seam (registers 30/31 on\nthe short layout, 56/57 on the long one).",
            "format": "double"
          },
          "fertilizerFlow": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Current fertilizer flow in cm³/h (registers 32/33 short, 58/59 long). Scaled by the\nfertilizer meter's own volume per pulse — `cubicCentimetrePerPulse` —\nnot by the water meter's litres multiplier, which is what the water flow beside it\nuses.",
            "format": "double"
          },
          "totalIrrigation": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Accumulated irrigation total in cubic metres (registers 475/476 short, 846/847 long;\nLSW/MSW joined).",
            "format": "int64"
          },
          "totalWaterLeak": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Accumulated water-leak total in cubic metres (registers 477/478 short, 848/849 long).",
            "format": "int64"
          },
          "totalFertilizerLeak": {
            "description": "Accumulated fertilizer-leak total (registers 479/480 short, 850/851 long), carrying\nthe unit the dosing mode selects: hours when the controller doses by time and litres\nwhen it doses by quantity, exactly as a valve's fertilizer accumulator does.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "totalRinses": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Count of filter rinses performed (register 482 short, 853 long).",
            "format": "int32"
          },
          "remainingMinutesBetweenRinseCycles": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Minutes left until the next rinse cycle (register 277 short, 648 long).",
            "format": "int32"
          },
          "remainingMinutesBetweenRinseValves": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Minutes left before the rinse moves to its next valve (register 278 short, 649\nlong).",
            "format": "int32"
          },
          "remainingRinseTime": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Time left in the running rinse (register 279 short, 650 long). A device time value\nwhose stored resolution no source names, so it is published raw rather than\nguessed.",
            "format": "int32"
          },
          "rinseCyclesWithoutSuccess": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Count of rinse cycles that did not complete (register 376 short, 747 long).",
            "format": "int32"
          },
          "timeBetweenRinsesMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Configured minutes between rinses (register 382 short, 753 long) — counted against\nactual irrigation minutes, not the wall clock.",
            "format": "int32"
          },
          "rinseTimeBetweenValves": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Configured rinse hand-over time from valve to valve, in seconds (register 383 short,\n754 long).",
            "format": "int32"
          },
          "rinseDurationSeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Configured duration of one rinse, in seconds (register 384 short, 755 long).",
            "format": "int32"
          },
          "cubicCentimetrePerPulse": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Cubic centimetres one fertilizer-meter pulse stands for (register 379 short, 750\nlong; event 2504), the fertilizer twin of the controller's water litres-per-pulse.\nIt is also the scale `fertilizerFlow` is computed with, which is why the\nmember is named for the unit it carries rather than for the ratio it expresses.",
            "format": "int32"
          },
          "noIrrigationTime": {
            "type": "string",
            "description": "The configured no-irrigation window (register 381 short, 752 long; event 2506, \"a\ntime when watering is not allowed\"), stored as minutes from midnight and published\nas `HH:mm` — the same rendering the lighting clocks get, and the same one the\nevent carries."
          },
          "noPulsesAlarmDelayMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How long the controller waits, in minutes, before it raises a no-pulses alarm\n(register 276 short, 647 long; event 2399).",
            "format": "int32"
          },
          "uncontrolledFlowAlarmPulses": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many pulses the controller counts before it reports an uncontrolled flow\n(register 386 short, 757 long; event 2511).",
            "format": "int32"
          },
          "valvesMeteringWaterOnTimedIrrigation": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Numbers of the valves that meter water while irrigating by time (register 394 short,\n765 long; event 2519, \"measuring water when working by time\"). One bit per valve, as\nthe legacy handler reads it."
          },
          "openValves": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Numbers of the valves the controller reports as open, whether a program or a person\nopened them (register 1 bits 0-12, valves 1-13, events 717-729). The companion of\n`manuallyOpenedValves`, which narrows that to the hand-opened ones."
          },
          "isRinseValveOpen": {
            "type": "boolean",
            "description": "Whether the rinse valve is open (register 1 bit 13)."
          },
          "manuallyOpenedValves": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Numbers of the valves reported as opened manually (register 3 bits 0-12, valves\n1-13 — the register spends its three remaining bits on the rinse, fertilizer and\nmain valves below, so only thirteen numbered valves can carry the flag)."
          },
          "valveFaults": {
            "description": "Which valves are currently in which fault, from the eleven per-valve fault bitmaps\nof registers 4-14. Always present: no fault anywhere reads as eleven empty lists,\nwhich is the same answer the device gives.",
            "$ref": "#/components/schemas/ControllerIrrigationValveFaults"
          },
          "isRinseOpenedManually": {
            "type": "boolean",
            "description": "Whether the rinse valve was opened manually (register 3 bit 13)."
          },
          "isFertilizerValveOpenedManually": {
            "type": "boolean",
            "description": "Whether the fertilizer valve was opened manually (register 3 bit 14)."
          },
          "isMainValveOpenedManually": {
            "type": "boolean",
            "description": "Whether the main valve was opened manually (register 3 bit 15)."
          },
          "isRinsing": {
            "type": "boolean",
            "description": "Whether the filter is rinsing right now (register 0 bit 0)."
          },
          "isWaitingForRinsingMode": {
            "type": "boolean",
            "description": "Whether the controller is waiting to enter rinsing mode (register 0 bit 1)."
          },
          "isInRinsingCycle": {
            "type": "boolean",
            "description": "Whether the controller is currently within a rinsing cycle (register 0 bit 2)."
          },
          "isMainValveOpen": {
            "type": "boolean",
            "description": "Whether the main valve is open (register 0 bit 3)."
          },
          "isInRinsingTransition": {
            "type": "boolean",
            "description": "Whether the controller is transitioning between rinsing states (register 0 bit 4)."
          },
          "hasWaterLeak": {
            "type": "boolean",
            "description": "Whether a systemic water leak is detected (register 0 bit 5)."
          },
          "hasFertilizerLeak": {
            "type": "boolean",
            "description": "Whether a leak in the fertilization system is detected (register 0 bit 6)."
          },
          "isLowInputPressure": {
            "type": "boolean",
            "description": "Whether input pressure is missing (register 0 bit 7)."
          },
          "isProgramModeWithoutIrrigation": {
            "type": "boolean",
            "description": "Whether program mode is active without irrigation (register 0 bit 8). This is the\ndevice's reported fact; it is not inverted into a derived running-state flag."
          },
          "isFertilizerValveOpen": {
            "type": "boolean",
            "description": "Whether the fertilizer valve is open (register 0 bit 9)."
          },
          "isStoppedOnLowPressure": {
            "type": "boolean",
            "description": "Whether the system stopped itself on low pressure (register 0 bit 11)."
          },
          "isFrozen": {
            "type": "boolean",
            "description": "Whether the system is frozen (register 0 bit 10) — the old firmware's\ndisable flag, kept by newer firmware beside the system-disabled bit. The legacy\nconsumer treated frozen-or-disabled as one fact; both are published separately so\nnothing is derived."
          },
          "isIrrigatingOrRinsing": {
            "type": "boolean",
            "description": "Whether the system is irrigating or rinsing (register 0 bit 13 — the device reports\nthe two as one fact, so they are not split here)."
          },
          "generalAlarm": {
            "type": "boolean",
            "description": "The general-alarm status bit (register 0 bit 14), as on LT and DM."
          },
          "isLowVoltage": {
            "type": "boolean",
            "description": "Whether the supply voltage is low (register 0 bit 15)."
          },
          "valves": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerIrrigationValve"
            },
            "description": "The configured valves, in valve order, read from the per-valve register runs of the\n548-register layout. Empty on the 1066-register layout, which stores the same runs\nbut carries no valve list to hang them on."
          },
          "programs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerIrrigationProgram"
            },
            "description": "Programs reconstructed from the valves, earliest start first."
          },
          "configurationErrors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What did not add up while reconstructing the programs — a valve claimed twice, a\nfactor that disagrees with its program, a start-with pointing at itself. Reported\nrather than thrown: an inconsistent controller still has readable state, and hiding\nthe inconsistency is what makes it hard to find."
          }
        },
        "description": "`I1`-only subsystem detail: the controller clock, whether a main valve is fitted,\nand — on the short layout, the only one that carries the valve configuration registers —\nthe valves and the programs reconstructed from them.",
        "x-controller-values": {
          "clockMinutesFromMidnight": {
            "kind": "clock",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "minutes from midnight",
            "source": "I1 short register 179; long register 550",
            "events": [
              2302
            ],
            "evidence": "i1.summary"
          },
          "dayOfWeek": {
            "kind": "codedState",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw code; 1=sunday through 7=saturday",
            "source": "I1 short register 178; long register 549",
            "events": [
              2301
            ],
            "evidence": "i1.summary"
          },
          "hasMainValve": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 17 bit 0; long register 43 bit 0",
            "events": [
              1517,
              1617
            ],
            "evidence": "i1.summary"
          },
          "hardwarePortCount": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 40; long register 66",
            "events": [
              1713
            ],
            "evidence": "i1.summary"
          },
          "hasFilter": {
            "kind": "boolean",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw != 0",
            "source": "I1 short register 42; long register 68",
            "events": [
              1715
            ],
            "evidence": "i1.summary"
          },
          "filterCount": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 390; long register 761",
            "events": [
              2515
            ],
            "evidence": "i1.summary"
          },
          "hasFertilizerValve": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 17 bit 1; long register 43 bit 1",
            "events": [
              1518,
              1618
            ],
            "evidence": "i1.summary"
          },
          "supportsPulses": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 17 bit 2; long register 43 bit 2",
            "events": [
              1519,
              1619
            ],
            "evidence": "i1.summary"
          },
          "isFertilizerByTime": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 17 bit 6; long register 43 bit 6",
            "events": [ ],
            "evidence": "i1.dosing-behaviour"
          },
          "isFertilizerProportional": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 17 bit 7; long register 43 bit 7",
            "events": [ ],
            "evidence": "i1.dosing-behaviour"
          },
          "isRinsingBlockedDuringPipeFill": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 17 bit 5; long register 43 bit 5",
            "events": [ ],
            "evidence": "i1.dosing-behaviour"
          },
          "isWaterMeterInputOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 2 bit 0",
            "events": [
              733,
              833
            ],
            "evidence": "i1.meter-inputs"
          },
          "isFertilizerMeterInputOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 2 bit 1",
            "events": [
              734,
              834
            ],
            "evidence": "i1.meter-inputs"
          },
          "isPressureMeterInputOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 2 bit 2",
            "events": [
              735,
              835
            ],
            "evidence": "i1.meter-inputs"
          },
          "isPressureDifferentialMeterInputOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 2 bit 3",
            "events": [
              736,
              836
            ],
            "evidence": "i1.meter-inputs"
          },
          "controllerAddress": {
            "kind": "number",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 39; long register 65",
            "events": [
              1712
            ],
            "evidence": "i1.summary"
          },
          "irrigatingValveNumber": {
            "kind": "number",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 37; long register 63",
            "events": [
              1710
            ],
            "evidence": "i1.activity"
          },
          "filterWashBehaviour": {
            "kind": "enum",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "bit 0 continues irrigation, bit 1 stops fertilizing only; both set is unused",
            "source": "I1 short register 18 bits 0-1; long register 44 bits 0-1",
            "events": [
              1533,
              1534,
              1633,
              1634
            ],
            "evidence": "i1.filter-wash-behaviour"
          },
          "highFlowBehaviour": {
            "kind": "enum",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "behaviour bit 5 pauses the program instead of closing the valve; register 393 bit 2 disables the valve unit",
            "source": "I1 short register 18 bit 5 and register 393 bit 2; long register 44 bit 5 and register 764 bit 2",
            "events": [
              1538,
              1638,
              2518
            ],
            "evidence": "i1.high-flow-behaviour"
          },
          "continuesIrrigationOnFertilizerFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 18 bit 2; long register 44 bit 2",
            "events": [
              1535,
              1635
            ],
            "evidence": "i1.behaviour-flags"
          },
          "opensMainValveBeforeValves": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 18 bit 3; long register 44 bit 3",
            "events": [
              1536,
              1636
            ],
            "evidence": "i1.behaviour-flags"
          },
          "opensMainValveAfterValves": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 18 bit 4; long register 44 bit 4",
            "events": [
              1537,
              1637
            ],
            "evidence": "i1.behaviour-flags"
          },
          "allowsValveGrouping": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 18 bit 7; long register 44 bit 7",
            "events": [
              1540,
              1640
            ],
            "evidence": "i1.behaviour-flags"
          },
          "isExternalPowerConnected": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 15 bit 1",
            "events": [
              1150,
              1250
            ],
            "evidence": "i1.power-input-bits"
          },
          "isCharging": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 15 bit 4",
            "events": [
              1153,
              1253
            ],
            "evidence": "i1.power-input-bits"
          },
          "externalPowerVoltage": {
            "kind": "number",
            "origin": "register",
            "unit": "volts",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "I1 short register 29; long register 55",
            "events": [
              1702
            ],
            "evidence": "i1.external-power-voltage"
          },
          "autoNominalFlowChangePercent": {
            "kind": "number",
            "origin": "register",
            "unit": "percent",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 80; long register 451",
            "events": [
              1802
            ],
            "evidence": "i1.flow-totals"
          },
          "mainValveDelaySeconds": {
            "kind": "number",
            "origin": "register",
            "unit": "seconds",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 377; long register 748",
            "events": [
              2502
            ],
            "evidence": "i1.valve-configuration"
          },
          "valveOpenVoltage": {
            "kind": "number",
            "origin": "packedRegister",
            "unit": "volts",
            "unitSource": "",
            "encoding": "low byte / 10",
            "source": "I1 short register 79 low byte",
            "events": [
              1801
            ],
            "evidence": "i1.valve-configuration"
          },
          "valveOpenTimeMs": {
            "kind": "number",
            "origin": "packedRegister",
            "unit": "milliseconds",
            "unitSource": "",
            "encoding": "high byte",
            "source": "I1 short register 79 high byte",
            "events": [
              1801
            ],
            "evidence": "i1.valve-configuration"
          },
          "currentFlow": {
            "kind": "number",
            "origin": "registerPair",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "(LSW + (MSW << 16)) * litresPerUnit / 1000",
            "source": "I1 short registers 30-31; long registers 56-57",
            "events": [
              1703,
              1704
            ],
            "evidence": "i1.flow-totals"
          },
          "fertilizerFlow": {
            "kind": "number",
            "origin": "registerPair",
            "unit": "cubicCentimetrePerHour",
            "unitSource": "",
            "encoding": "(LSW + (MSW << 16)) * cubicCentimetrePerPulse / 1000",
            "source": "I1 short registers 32-33; long registers 58-59",
            "events": [
              1705,
              1706
            ],
            "evidence": "i1.flow-totals"
          },
          "totalIrrigation": {
            "kind": "number",
            "origin": "registerPair",
            "unit": "cubicMetres",
            "unitSource": "",
            "encoding": "LSW + (MSW << 16)",
            "source": "I1 short registers 475-476; long registers 846-847",
            "events": [
              1901,
              1902
            ],
            "evidence": "i1.flow-totals"
          },
          "totalWaterLeak": {
            "kind": "number",
            "origin": "registerPair",
            "unit": "cubicMetres",
            "unitSource": "",
            "encoding": "LSW + (MSW << 16)",
            "source": "I1 short registers 477-478; long registers 848-849",
            "events": [
              1903,
              1904
            ],
            "evidence": "i1.flow-totals"
          },
          "totalFertilizerLeak": {
            "kind": "measuredValue",
            "origin": "registerPair",
            "unit": "modeDependent",
            "unitSource": "fertilization-by-time setup register 17 bit 6 (long layout register 43 bit 6)",
            "encoding": "LSW + (MSW << 16)",
            "source": "I1 short registers 479-480; long registers 850-851",
            "events": [
              1905,
              1906
            ],
            "evidence": "i1.flow-totals"
          },
          "totalRinses": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 482; long register 853",
            "events": [
              1908
            ],
            "evidence": "i1.rinsing"
          },
          "remainingMinutesBetweenRinseCycles": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 277; long register 648",
            "events": [
              2401
            ],
            "evidence": "i1.rinsing"
          },
          "remainingMinutesBetweenRinseValves": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 278; long register 649",
            "events": [
              2402
            ],
            "evidence": "i1.rinsing"
          },
          "remainingRinseTime": {
            "kind": "number",
            "origin": "register",
            "unit": "unconfirmed",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 279; long register 650",
            "events": [
              2403
            ],
            "evidence": "i1.rinsing"
          },
          "rinseCyclesWithoutSuccess": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 376; long register 747",
            "events": [
              2501
            ],
            "evidence": "i1.rinsing"
          },
          "timeBetweenRinsesMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 382; long register 753",
            "events": [
              2507
            ],
            "evidence": "i1.rinsing"
          },
          "rinseTimeBetweenValves": {
            "kind": "number",
            "origin": "register",
            "unit": "seconds",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 383; long register 754",
            "events": [
              2508
            ],
            "evidence": "i1.rinsing"
          },
          "rinseDurationSeconds": {
            "kind": "number",
            "origin": "register",
            "unit": "seconds",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 384; long register 755",
            "events": [
              2509
            ],
            "evidence": "i1.rinsing"
          },
          "cubicCentimetrePerPulse": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicCentimetre",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 379; long register 750",
            "events": [
              2504
            ],
            "evidence": "i1.metering-setup"
          },
          "noIrrigationTime": {
            "kind": "clock",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "minutes from midnight, rendered HH:mm",
            "source": "I1 short register 381; long register 752",
            "events": [
              2506
            ],
            "evidence": "i1.no-irrigation-window"
          },
          "noPulsesAlarmDelayMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 276; long register 647",
            "events": [
              2399
            ],
            "evidence": "i1.no-pulse-delay"
          },
          "uncontrolledFlowAlarmPulses": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 386; long register 757",
            "events": [
              2511
            ],
            "evidence": "i1.no-pulse-delay"
          },
          "valvesMeteringWaterOnTimedIrrigation": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 0-15 become one-based valve numbers",
            "source": "I1 short register 394; long register 765",
            "events": [
              2519
            ],
            "evidence": "i1.metering-setup"
          },
          "openValves": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 0-12 become one-based valve numbers",
            "source": "I1 register 1 bits 0-12",
            "events": [
              717
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isRinseValveOpen": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 1 bit 13",
            "events": [
              730,
              830
            ],
            "evidence": "i1.status-bitmaps"
          },
          "manuallyOpenedValves": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 0-12 become one-based valve numbers",
            "source": "I1 register 3 bits 0-12",
            "events": [
              749
            ],
            "evidence": "i1.status-bitmaps"
          },
          "valveFaults": {
            "kind": "objectGroup",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 registers 4-14",
            "events": [ ],
            "evidence": "i1.valve-faults"
          },
          "isRinseOpenedManually": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 3 bit 13",
            "events": [
              762,
              862
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isFertilizerValveOpenedManually": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 3 bit 14",
            "events": [
              763,
              863
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isMainValveOpenedManually": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 3 bit 15",
            "events": [
              764,
              864
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isRinsing": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 0",
            "events": [
              701,
              801
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isWaitingForRinsingMode": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 1",
            "events": [
              702,
              802
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isInRinsingCycle": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 2",
            "events": [
              703,
              803
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isMainValveOpen": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 3",
            "events": [
              704,
              804
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isInRinsingTransition": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 4",
            "events": [
              705,
              805
            ],
            "evidence": "i1.status-bitmaps"
          },
          "hasWaterLeak": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 5",
            "events": [
              706,
              806
            ],
            "evidence": "i1.status-bitmaps"
          },
          "hasFertilizerLeak": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 6",
            "events": [
              707,
              807
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isLowInputPressure": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 7",
            "events": [
              708,
              808
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isProgramModeWithoutIrrigation": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 8",
            "events": [
              709,
              809
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isFertilizerValveOpen": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 9",
            "events": [
              710,
              810
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isStoppedOnLowPressure": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 11",
            "events": [
              712,
              812
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isFrozen": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 10",
            "events": [
              711,
              811
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isIrrigatingOrRinsing": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 13",
            "events": [
              714,
              814
            ],
            "evidence": "i1.status-bitmaps"
          },
          "generalAlarm": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 14",
            "events": [
              715,
              815
            ],
            "evidence": "i1.status-bitmaps"
          },
          "isLowVoltage": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 register 0 bit 15",
            "events": [
              716,
              816
            ],
            "evidence": "i1.status-bitmaps"
          },
          "valves": {
            "kind": "collection",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short-layout per-valve register blocks",
            "events": [ ],
            "evidence": "i1.valve-configuration"
          },
          "programs": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 valve scheduling configuration",
            "events": [ ],
            "evidence": "i1.programs"
          },
          "configurationErrors": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 program reconstruction validation",
            "events": [ ],
            "evidence": "i1.programs"
          }
        }
      },
      "ControllerIrrigationValve": {
        "required": [
          "amount",
          "amountLeft",
          "amountBeforeFertilizing",
          "amountAfterFertilizing",
          "fertilizerAmount",
          "fertilizerAmountLeft",
          "totalFertilizer"
        ],
        "type": "object",
        "properties": {
          "number": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One-based valve number, as the controller labels it. Not a register of its own: it\nis the slot the valve occupies, and every per-valve register below is read at its\nbase index plus this number minus one.",
            "format": "int32"
          },
          "isActive": {
            "type": "boolean",
            "description": "True when the valve is within the controller's active-valve count. Valves past it\nstill hold register values, but the controller does not run them."
          },
          "isDisabled": {
            "type": "boolean",
            "description": "Whether the valve is disabled in configuration, so the controller will not run\nit. One bit per valve in a single register (392), the valve's own number\nselecting the bit, counting from zero. The long layout stores the same bitmap\nat 763, but carries no valve list to hang it on."
          },
          "amount": {
            "description": "The configured amount (register 312 plus the valve slot), scaled to and carrying the\nunit the method implies: minutes or seconds on a timed valve (the controller's general\ntime-units setup selects which), cubic metres on a volume one (the register holds\nhundredths).",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "amountLeft": {
            "description": "What remains of the running irrigation (register 114 plus the valve slot): the\ncontroller loads the configured amount when the valve starts and counts this down to\nzero, so a premature stop leaves it non-zero. Minutes on a timed valve and cubic metres\non a volume one, exactly as the amount; the volume register counts units of the\ncontroller's litres multiplier and is scaled here, and the published value names its\nunit beside it.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "amountBeforeFertilizing": {
            "description": "Water to pass before fertilizing starts (register 328 plus the valve slot, events\n2452-2467), in the configured amount's unit: cubic metres from hundredths on a\nvolume valve, raw minutes or seconds on a timed one.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "amountAfterFertilizing": {
            "description": "Water to pass after fertilizing ends (register 344 plus the valve slot, events\n2468-2483), scaled and unit-tagged exactly as the amount before fertilizing.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "cycleDays": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Length of this valve's irrigation cycle in days (register 228 plus the valve slot,\nevents 2351-2366), the interval the weekday list does not express.",
            "format": "int32"
          },
          "cycleDaysLeft": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Days left until this valve's cycle completes (register 146 plus the valve slot,\nevents 1868-1883).",
            "format": "int32"
          },
          "fertilizerAmount": {
            "description": "Configured fertilizer amount (register 360 plus the valve slot; the register holds\nhundredths), carrying the unit the dosing mode selects: minutes when the controller\ndoses by time and litres when it doses by quantity.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "fertilizerAmountLeft": {
            "description": "What is left of that fertilizer dose (register 130 plus the valve slot), in the same\nhundredths and the same mode-selected unit the configured amount is stored in. Loaded\nwhen the valve starts dosing and counted down, so a non-zero value after a run means\nthe dose did not complete.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "totalIrrigation": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Everything this valve has irrigated since the accumulator was last reset (registers\n484/485 plus twice the valve slot, joined low word first). Cubic metres: the shipped\nclient's accumulator table heads the column with the unit and applies no scaling to\nthe joined value.",
            "format": "int64"
          },
          "totalFertilizer": {
            "description": "Everything this valve has dosed since the accumulator was last reset (registers\n516/517 plus twice the valve slot, joined low word first), carrying the unit the\ndosing mode selects: hours when the controller doses by time and litres when it doses\nby quantity. Both are small numbers in the same range, which is why the value travels\nwith its unit instead of leaving every consumer to re-derive it.",
            "$ref": "#/components/schemas/ControllerMeasuredValue"
          },
          "pulseCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many irrigation pulses the valve runs (register 395 plus the valve slot;\ndevice events 2520-2535). Read on the 548-register layout only, like the rest\nof the valve block.",
            "format": "int32"
          },
          "pulseIntervalMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Minutes between those pulses (register 411 plus the valve slot; device events\n2536-2551). Read on the 548-register layout only.",
            "format": "int32"
          },
          "pulseCountLeft": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many of those pulses are still to run (register 82 plus the valve slot; device\nevents 1804-1819) — the running counterpart of `pulseCount`. Both mapping\nfiles name it `SP_NumSplashCyclesRemainValve_N`; the legacy handler reads it raw.",
            "format": "int32"
          },
          "pulseIntervalLeft": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Minutes until the next pulse (register 98 plus the valve slot; device events\n1820-1835), the running counterpart of `pulseIntervalMinutes` and stored in the\nsame unit. The mapping files' variable name says days\n(`SP_NumDaysNextSplashValve_N`); the register documentation names minutes, which\nis also what the set point it counts down from is in.",
            "format": "int32"
          },
          "irrigationFactorPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Per-program irrigation-change percentage applied to every amount (register 459 plus\nthe valve slot). Every non-`with` valve of a program must agree on it; a\ndisagreement is reported as a configuration error.",
            "format": "int32"
          },
          "flowMinimum": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Configured minimum flow in m³/h (the register holds hundredths).",
            "format": "double"
          },
          "flowNominal": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Configured nominal flow in m³/h (the register holds hundredths).",
            "format": "double"
          },
          "flowMaximum": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Configured maximum flow in m³/h (the register holds hundredths).",
            "format": "double"
          },
          "lastFlow": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "The last flow the controller calculated for this valve, in m³/h. The register\nholds tenths — unlike the three configured flows above, which hold hundredths —\nbecause that is how both legacy readers of it divide (see the evidence row).",
            "format": "double"
          },
          "lowFlowAlarmDelayMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Delay in minutes before the low-flow alarm raises (register 427 plus the valve\nslot) — a duration, not a flow threshold.",
            "format": "int32"
          },
          "highFlowAlarmDelayMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Delay in minutes before the high-flow alarm raises (register 443 plus the valve\nslot).",
            "format": "int32"
          },
          "fillTimeMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Pipe fill time for this valve, in minutes — how long the line takes to pressurise\nbefore flow measurement is meaningful.",
            "format": "int32"
          },
          "startTimeMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Program start, in minutes from midnight (register 260 plus the valve slot).\nMeaningful only for a first valve.",
            "format": "int32"
          },
          "startTime": {
            "type": "string",
            "description": "The same program start as a time of day, `HH:mm` (600 minutes is\n`10:00`). Rendered beside `startTimeMinutes` rather than instead\nof it: the minutes stay the sortable number, and this is what a screen shows.\nRendered once here, as `noIrrigationTime` is, so REST and the hub cannot\nspell one register two ways. Like the minutes, meaningful only for a first valve."
          },
          "startWeekDays": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerCodedState"
            },
            "description": "The weekdays the valve irrigates on — bits 0-6 of the weekly-schedule register (244\nplus the valve slot; events 2367-2382), as Sunday-first coded pairs (`1` =\n`sunday` … `7` = `saturday`); empty when the valve does not start a\nprogram of its own. The same register's high byte carries\n`fertilizationWeekDays`."
          },
          "fertilizationWeekDays": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerCodedState"
            },
            "description": "The weekdays the valve fertilizes on — bits 8-14 of the same weekly-schedule\nregister, in the same Sunday-first vocabulary. Bits 7 and 15 are reserved. A valve\nwhose register holds the reserved \"scheduled by another valve\" value reports no\nfertilization days rather than all seven, for the reason its start days are empty."
          },
          "startDayRegister": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Raw weekly-schedule register. Kept alongside the two decoded day lists because the\nweekday bits alone cannot express the reserved value that marks a valve as scheduled\nby another one — decoding it would show a valve starting every day when it starts\non none.",
            "format": "int32"
          },
          "startAfterValve": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Valve number this one follows (register 280 plus the valve slot), or 0 when it\nstarts on its own schedule.",
            "format": "int32"
          },
          "startWithValves": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valve numbers that open together with this one, from the bitmap at register 296 plus\nthe valve slot — one bit per valve, counting from zero."
          },
          "role": {
            "description": "The part a valve plays in the programs decoded from a controller's registers. Derived,\nnot stored: the controller records start days, a predecessor and a \"start with\" mask,\nand the role follows from them.",
            "$ref": "#/components/schemas/ControllerIrrigationValveRole"
          }
        },
        "description": "One irrigation valve of an `I1` controller: its configured amount, its flow\nenvelope, and how it is scheduled relative to the other valves.",
        "x-controller-values": {
          "number": {
            "kind": "number",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "one-based slot number",
            "source": "I1 valve register slot",
            "events": [ ],
            "evidence": "i1.valve-configuration"
          },
          "isActive": {
            "kind": "boolean",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "valve number <= active-valve count",
            "source": "I1 valve slot and short register 389",
            "events": [ ],
            "evidence": "i1.valve-configuration"
          },
          "isDisabled": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short register 392 bit selected by valve slot",
            "events": [
              2517
            ],
            "evidence": "i1.valve-configuration"
          },
          "amount": {
            "kind": "measuredValue",
            "origin": "derived",
            "unit": "modeDependent",
            "unitSource": "method register 19 bit per valve; general time-units setup register 17 bit 3",
            "encoding": "volume: raw / 100; timed: raw with minutes or seconds selected by setup bit 3",
            "source": "I1 short registers 312-327",
            "events": [
              2436
            ],
            "evidence": "i1.valve-amount"
          },
          "amountLeft": {
            "kind": "measuredValue",
            "origin": "derived",
            "unit": "modeDependent",
            "unitSource": "method register 19 bit per valve; general time-units setup register 17 bit 3",
            "encoding": "volume: raw * litresPerUnit / 1000; timed: raw with minutes or seconds selected by setup bit 3",
            "source": "I1 short registers 114-129",
            "events": [
              1836
            ],
            "evidence": "i1.valve-amount"
          },
          "amountBeforeFertilizing": {
            "kind": "measuredValue",
            "origin": "derived",
            "unit": "modeDependent",
            "unitSource": "method register 19 bit per valve; general time-units setup register 17 bit 3",
            "encoding": "volume: raw / 100; timed: raw with minutes or seconds selected by setup bit 3",
            "source": "I1 short registers 328-343",
            "events": [
              2452
            ],
            "evidence": "i1.valve-amount"
          },
          "amountAfterFertilizing": {
            "kind": "measuredValue",
            "origin": "derived",
            "unit": "modeDependent",
            "unitSource": "method register 19 bit per valve; general time-units setup register 17 bit 3",
            "encoding": "volume: raw / 100; timed: raw with minutes or seconds selected by setup bit 3",
            "source": "I1 short registers 344-359",
            "events": [
              2468
            ],
            "evidence": "i1.valve-amount"
          },
          "cycleDays": {
            "kind": "number",
            "origin": "register",
            "unit": "days",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 228-243",
            "events": [
              2351
            ],
            "evidence": "i1.valve-cycle-days"
          },
          "cycleDaysLeft": {
            "kind": "number",
            "origin": "register",
            "unit": "days",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 146-161",
            "events": [
              1868
            ],
            "evidence": "i1.valve-cycle-days"
          },
          "fertilizerAmount": {
            "kind": "measuredValue",
            "origin": "register",
            "unit": "modeDependent",
            "unitSource": "fertilization-by-time setup register 17 bit 6 (long layout register 43 bit 6)",
            "encoding": "raw / 100",
            "source": "I1 short registers 360-375",
            "events": [
              2484
            ],
            "evidence": "i1.valve-configuration"
          },
          "fertilizerAmountLeft": {
            "kind": "measuredValue",
            "origin": "register",
            "unit": "modeDependent",
            "unitSource": "fertilization-by-time setup register 17 bit 6 (long layout register 43 bit 6)",
            "encoding": "raw / 100",
            "source": "I1 short registers 130-145",
            "events": [
              1852
            ],
            "evidence": "i1.valve-configuration"
          },
          "totalIrrigation": {
            "kind": "number",
            "origin": "registerPair",
            "unit": "cubicMetres",
            "unitSource": "",
            "encoding": "LSW + (MSW << 16)",
            "source": "I1 short registers 484-515, two per valve",
            "events": [
              1910,
              1911
            ],
            "evidence": "i1.valve-accumulators"
          },
          "totalFertilizer": {
            "kind": "measuredValue",
            "origin": "registerPair",
            "unit": "modeDependent",
            "unitSource": "fertilization-by-time setup register 17 bit 6 (long layout register 43 bit 6)",
            "encoding": "LSW + (MSW << 16)",
            "source": "I1 short registers 516-547, two per valve",
            "events": [
              1942,
              1943
            ],
            "evidence": "i1.valve-accumulators"
          },
          "pulseCount": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 395-410",
            "events": [
              2520
            ],
            "evidence": "i1.valve-configuration"
          },
          "pulseIntervalMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 411-426",
            "events": [
              2536
            ],
            "evidence": "i1.valve-configuration"
          },
          "pulseCountLeft": {
            "kind": "count",
            "origin": "register",
            "unit": "count",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 82-97",
            "events": [
              1804
            ],
            "evidence": "i1.pulse-countdowns"
          },
          "pulseIntervalLeft": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 98-113",
            "events": [
              1820
            ],
            "evidence": "i1.pulse-countdowns"
          },
          "irrigationFactorPercent": {
            "kind": "number",
            "origin": "register",
            "unit": "percent",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 459-474",
            "events": [
              2584
            ],
            "evidence": "i1.valve-configuration"
          },
          "flowMinimum": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "raw / 100",
            "source": "I1 short registers 180-195",
            "events": [
              2303
            ],
            "evidence": "i1.valve-configuration"
          },
          "flowNominal": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "raw / 100",
            "source": "I1 short registers 196-211",
            "events": [
              2319
            ],
            "evidence": "i1.valve-configuration"
          },
          "flowMaximum": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "raw / 100",
            "source": "I1 short registers 212-227",
            "events": [
              2335
            ],
            "evidence": "i1.valve-configuration"
          },
          "lastFlow": {
            "kind": "number",
            "origin": "register",
            "unit": "cubicMetresPerHour",
            "unitSource": "",
            "encoding": "raw / 10",
            "source": "I1 short registers 60-75",
            "events": [
              1733
            ],
            "evidence": "i1.valve-last-flow"
          },
          "lowFlowAlarmDelayMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 427-442",
            "events": [
              2552
            ],
            "evidence": "i1.valve-configuration"
          },
          "highFlowAlarmDelayMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 443-458",
            "events": [
              2568
            ],
            "evidence": "i1.valve-configuration"
          },
          "fillTimeMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "raw",
            "source": "I1 short registers 162-177",
            "events": [
              1884
            ],
            "evidence": "i1.valve-configuration"
          },
          "startTimeMinutes": {
            "kind": "clock",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "minutes from midnight",
            "source": "I1 short registers 260-275",
            "events": [
              2383
            ],
            "evidence": "i1.valve-configuration"
          },
          "startTime": {
            "kind": "clock",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "startTimeMinutes rendered HH:mm",
            "source": "I1 short registers 260-275",
            "events": [ ],
            "evidence": "i1.valve-configuration"
          },
          "startWeekDays": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 0-6 (register & 0x7F) become Sunday-first coded days",
            "source": "I1 short registers 244-259",
            "events": [ ],
            "evidence": "i1.valve-weekly-schedule"
          },
          "fertilizationWeekDays": {
            "kind": "collection",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "bits 8-14 ((register >> 8) & 0x7F) become Sunday-first coded days",
            "source": "I1 short registers 244-259",
            "events": [ ],
            "evidence": "i1.valve-weekly-schedule"
          },
          "startDayRegister": {
            "kind": "number",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw packed bitmap: irrigation days bits 0-6, fertilization days bits 8-14, bits 7 and 15 reserved; 0x7F7F marks a valve scheduled by another",
            "source": "I1 short registers 244-259",
            "events": [
              2367
            ],
            "evidence": "i1.valve-weekly-schedule"
          },
          "startAfterValve": {
            "kind": "number",
            "origin": "register",
            "unit": "none",
            "unitSource": "",
            "encoding": "one-based valve number; 0 means none",
            "source": "I1 short registers 280-295",
            "events": [
              2404
            ],
            "evidence": "i1.valve-configuration"
          },
          "startWithValves": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 short registers 296-311",
            "events": [
              2420
            ],
            "evidence": "i1.valve-configuration"
          },
          "role": {
            "kind": "enum",
            "origin": "derived",
            "unit": "none",
            "unitSource": "",
            "encoding": "program linkage classification",
            "source": "I1 valve scheduling configuration",
            "events": [ ],
            "evidence": "i1.programs"
          }
        }
      },
      "ControllerIrrigationValveFaults": {
        "type": "object",
        "properties": {
          "chainingProblem": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves reporting a chaining/sequence problem (register 4, events 765-780)."
          },
          "highFlowAlarm": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves reporting a high-flow alarm (register 5, events 781-796). The controller\nfirmware names it `CRC_REG__ALARM_FLOW_HI_BMP__005` and documents exactly those\nevents, with off twins 881-896."
          },
          "lowFlowAlarm": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves reporting a low-flow alarm (register 6, events 901-916)."
          },
          "fertilizerMissing": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves reporting missing fertilizer material (register 7, events 917-932)."
          },
          "stoppedOnTimeLimit": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves the controller stopped because they reached their time limit (register 8,\nevents 933-948)."
          },
          "fertilizerLeak": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves reporting a leak in the fertilization system (register 9, events 949-964).\nThe per-valve companion of the controller-wide `hasFertilizerLeak` bit."
          },
          "stoppedOnLowPressure": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves the controller stopped for lack of pressure (register 10, events 965-980).\nThe per-valve companion of the controller-wide `isStoppedOnLowPressure` bit."
          },
          "frozen": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves held frozen (register 11, events 981-996) — the per-valve companion of the\ncontroller-wide `isFrozen` bit."
          },
          "fertilizerDelayed": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves whose fertilization is delayed by the cyclic rule (register 12, events\n1101-1116)."
          },
          "irrigatedWithoutFertilizer": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves that irrigated on without their fertilizer (register 13, events 1117-1132).\nDistinct from `fertilizerMissing`: this one says the controller carried on\nregardless."
          },
          "noPulses": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Valves reporting no water-meter pulses (register 14, events 1133-1148)."
          }
        },
        "description": "The irrigation controller's per-valve fault bitmaps: registers 4-14, eleven registers of\nthe status zone that each spend one bit per valve on one kind of fault. A set bit means\nthat valve is currently in that fault; the device raises the on event when it sets and\nthe off twin when it clears.",
        "x-controller-values": {
          "chainingProblem": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 4 bits 0-15",
            "events": [
              765
            ],
            "evidence": "i1.valve-faults"
          },
          "highFlowAlarm": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 5 bits 0-15",
            "events": [
              781
            ],
            "evidence": "i1.valve-faults"
          },
          "lowFlowAlarm": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 6 bits 0-15",
            "events": [
              901
            ],
            "evidence": "i1.valve-faults"
          },
          "fertilizerMissing": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 7 bits 0-15",
            "events": [
              917
            ],
            "evidence": "i1.valve-faults"
          },
          "stoppedOnTimeLimit": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 8 bits 0-15",
            "events": [
              933
            ],
            "evidence": "i1.valve-faults"
          },
          "fertilizerLeak": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 9 bits 0-15",
            "events": [
              949
            ],
            "evidence": "i1.valve-faults"
          },
          "stoppedOnLowPressure": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 10 bits 0-15",
            "events": [
              965
            ],
            "evidence": "i1.valve-faults"
          },
          "frozen": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 11 bits 0-15",
            "events": [
              981
            ],
            "evidence": "i1.valve-faults"
          },
          "fertilizerDelayed": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 12 bits 0-15",
            "events": [
              1101
            ],
            "evidence": "i1.valve-faults"
          },
          "irrigatedWithoutFertilizer": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 13 bits 0-15",
            "events": [
              1117
            ],
            "evidence": "i1.valve-faults"
          },
          "noPulses": {
            "kind": "collection",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "set bits become one-based valve numbers",
            "source": "I1 register 14 bits 0-15",
            "events": [
              1133
            ],
            "evidence": "i1.valve-faults"
          }
        }
      },
      "ControllerIrrigationValveRole": {
        "enum": [
          "unassigned",
          "first",
          "next",
          "with"
        ],
        "description": "The part a valve plays in the programs decoded from a controller's registers. Derived,\nnot stored: the controller records start days, a predecessor and a \"start with\" mask,\nand the role follows from them."
      },
      "ControllerItemResponse": {
        "required": [
          "id",
          "name"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerMetadataResponse"
              }
            ]
          },
          "area": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerAreaResponse"
              }
            ]
          },
          "connections": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerConnectionsResponse"
              }
            ]
          },
          "tollGates": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerTollGatesResponse"
              }
            ]
          },
          "junctions": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerJunctionsResponse"
              }
            ]
          },
          "location": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerLocationResponse"
              }
            ]
          }
        },
        "additionalProperties": false,
        "description": "One controller in the pilot list, any model. The identity core (id, name, metadata,\nlocation) is present for every model; the LT static groups (area, connections, toll\ngates, junctions) appear only for LT lighting controllers. State is available only\nfrom the state-refresh endpoint or controller-states hub. Null-valued properties are omitted on the wire;\ngroups are omitted rather than zero-faked."
      },
      "ControllerJunctionsResponse": {
        "type": "object",
        "properties": {
          "junction1": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the first road junction fed from this cabinet, as the RECO database\nrecords it. A cabinet detail, not a register."
          },
          "junction2": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the second junction fed from this cabinet. Database detail."
          },
          "junction3": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the third junction fed from this cabinet. Database detail."
          }
        },
        "additionalProperties": false
      },
      "ControllerLightingCircuit": {
        "type": "object",
        "properties": {
          "isOn": {
            "type": "boolean",
            "description": "The circuit is energised."
          },
          "hasError": {
            "type": "boolean",
            "description": "The controller reports a fault on this circuit."
          },
          "isDisabled": {
            "type": "boolean",
            "description": "The circuit is disabled in configuration, so it will not switch on."
          }
        },
        "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags.",
        "x-controller-values": {
          "isOn": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT circuit on bits in register 1",
            "events": [
              730,
              731,
              732,
              830,
              831,
              832
            ],
            "evidence": "lt.subsystems"
          },
          "hasError": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT circuit fault bit in register 1",
            "events": [
              725,
              726,
              727,
              825,
              826,
              827
            ],
            "evidence": "lt.subsystems"
          },
          "isDisabled": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT circuit disable bit in register 43",
            "events": [
              1517,
              1518,
              1519,
              1617,
              1618,
              1619
            ],
            "evidence": "lt.subsystems"
          }
        }
      },
      "ControllerLightingReading": {
        "required": [
          "mainSwitch",
          "nonEssentialLighting",
          "essentialLighting",
          "generatorBackupLighting",
          "generator",
          "schedule"
        ],
        "type": "object",
        "properties": {
          "generalAlarm": {
            "type": "boolean",
            "description": "The controller's general alarm bit."
          },
          "communicationFault": {
            "type": "boolean",
            "description": "The controller detects a communication fault (register 0 bit 15) — the same bit DM\nreports under the same name."
          },
          "isControlledByLocalClock": {
            "type": "boolean",
            "description": "Lighting is switched by the controller's own clock rather than commanded."
          },
          "isWaterLevelLow": {
            "type": "boolean",
            "description": "Water level below threshold, reported alongside the generator status."
          },
          "mainSwitch": {
            "description": "Main-switch position of an LT controller, as three independent register bits.",
            "$ref": "#/components/schemas/ControllerMainSwitchState"
          },
          "nonEssentialLighting": {
            "description": "Ordinary street lighting, shed first when supply is constrained.",
            "$ref": "#/components/schemas/ControllerLightingCircuit"
          },
          "essentialLighting": {
            "description": "Lighting that must stay on, backed by the generator.",
            "$ref": "#/components/schemas/ControllerLightingCircuit"
          },
          "generatorBackupLighting": {
            "description": "The circuit the generator feeds directly.",
            "$ref": "#/components/schemas/ControllerLightingCircuit"
          },
          "generator": {
            "description": "Standby-generator status of an LT controller, decoded from the generator register.\nIt backs the essential lighting circuits when mains power fails, so its faults are\noperationally urgent even while the lights are still on.",
            "$ref": "#/components/schemas/ControllerGeneratorState"
          },
          "isCommunicationPowerDetected": {
            "type": "boolean",
            "description": "The communication controller's power detection bit."
          },
          "isCommunicationBatteryVoltageOk": {
            "type": "boolean",
            "description": "The communication controller reports its battery voltage in range."
          },
          "schedule": {
            "description": "Configured lighting schedule of an LT controller: the offsets and thresholds that\ndecide when the controller switches its circuits, read back exactly as configured.",
            "$ref": "#/components/schemas/ControllerLightingSchedule"
          }
        },
        "description": "Everything an LT (street-lighting) controller reports beyond the values every model\nshares. Present only for LT controllers on the 1066-register layout; other models and\nthe short layout leave it `null`.",
        "x-controller-values": {
          "generalAlarm": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 0 bit 14",
            "events": [
              715,
              815
            ],
            "evidence": "lt.cabinet-status"
          },
          "communicationFault": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 0 bit 15",
            "events": [
              716,
              816
            ],
            "evidence": "lt.cabinet-status"
          },
          "isControlledByLocalClock": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 1 bit 3",
            "events": [
              720,
              820
            ],
            "evidence": "lt.subsystems"
          },
          "isWaterLevelLow": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 bit 7",
            "events": [
              740,
              840
            ],
            "evidence": "lt.subsystems"
          },
          "mainSwitch": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 1 main-switch bits",
            "events": [ ],
            "evidence": "lt.subsystems"
          },
          "nonEssentialLighting": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT non-essential circuit status and control bits",
            "events": [ ],
            "evidence": "lt.subsystems"
          },
          "essentialLighting": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT essential circuit status and control bits",
            "events": [ ],
            "evidence": "lt.subsystems"
          },
          "generatorBackupLighting": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT generator-backup circuit status and control bits",
            "events": [ ],
            "evidence": "lt.subsystems"
          },
          "generator": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 2 generator bits",
            "events": [ ],
            "evidence": "lt.subsystems"
          },
          "isCommunicationPowerDetected": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 36 bit 1",
            "events": [
              3102,
              3202
            ],
            "evidence": "lt.subsystems"
          },
          "isCommunicationBatteryVoltageOk": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 36 bit 3",
            "events": [
              3104,
              3204
            ],
            "evidence": "lt.subsystems"
          },
          "schedule": {
            "kind": "objectGroup",
            "origin": "structure",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT registers 456-461",
            "events": [ ],
            "evidence": "lt.schedule"
          }
        }
      },
      "ControllerLightingSchedule": {
        "type": "object",
        "properties": {
          "onsetMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Minutes the light-on moment is shifted relative to the computed sunset.",
            "format": "int32"
          },
          "offsetMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Minutes the light-off moment is shifted relative to the computed sunrise.",
            "format": "int32"
          },
          "summerTimeStart": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Summer-time start, split from the controller's packed day/month register.",
                "$ref": "#/components/schemas/ControllerMonthDay"
              }
            ]
          },
          "summerTimeEnd": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Summer-time end, split from the controller's packed day/month register.",
                "$ref": "#/components/schemas/ControllerMonthDay"
              }
            ]
          },
          "doorStatusThresholdTime": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "How long a door state must persist before the controller reports it, in device\ntime units — no available source names the unit, so it is not guessed.",
            "format": "int32"
          },
          "lightStatusThresholdTime": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "How long a light state must persist before the controller reports it, in the same\nunnamed device time units.",
            "format": "int32"
          }
        },
        "description": "Configured lighting schedule of an LT controller: the offsets and thresholds that\ndecide when the controller switches its circuits, read back exactly as configured.",
        "x-controller-values": {
          "onsetMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "signed 16-bit",
            "source": "LT register 457",
            "events": [
              1808
            ],
            "evidence": "lt.schedule"
          },
          "offsetMinutes": {
            "kind": "number",
            "origin": "register",
            "unit": "minutes",
            "unitSource": "",
            "encoding": "signed 16-bit",
            "source": "LT register 456",
            "events": [
              1807
            ],
            "evidence": "lt.schedule"
          },
          "summerTimeStart": {
            "kind": "calendar",
            "origin": "packedRegister",
            "unit": "none",
            "unitSource": "",
            "encoding": "day * 100 + month",
            "source": "LT register 458",
            "events": [
              1809
            ],
            "evidence": "lt.schedule"
          },
          "summerTimeEnd": {
            "kind": "calendar",
            "origin": "packedRegister",
            "unit": "none",
            "unitSource": "",
            "encoding": "day * 100 + month",
            "source": "LT register 459",
            "events": [
              1810
            ],
            "evidence": "lt.schedule"
          },
          "doorStatusThresholdTime": {
            "kind": "number",
            "origin": "register",
            "unit": "unconfirmed",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 460",
            "events": [
              1811
            ],
            "evidence": "lt.threshold-units"
          },
          "lightStatusThresholdTime": {
            "kind": "number",
            "origin": "register",
            "unit": "unconfirmed",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 461",
            "events": [
              1812
            ],
            "evidence": "lt.threshold-units"
          }
        }
      },
      "ControllerLocationResponse": {
        "type": "object",
        "properties": {
          "latitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "longitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "ControllerMainSwitchState": {
        "type": "object",
        "properties": {
          "isLocalControl": {
            "type": "boolean",
            "description": "Switched to local control at the cabinet."
          },
          "isRemoteControl": {
            "type": "boolean",
            "description": "Switched to remote control."
          },
          "isOff": {
            "type": "boolean",
            "description": "Switched off."
          }
        },
        "description": "Main-switch position of an LT controller, as three independent register bits.",
        "x-controller-values": {
          "isLocalControl": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 1 bit 0",
            "events": [
              717,
              817
            ],
            "evidence": "lt.subsystems"
          },
          "isRemoteControl": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 1 bit 1",
            "events": [
              718,
              818
            ],
            "evidence": "lt.subsystems"
          },
          "isOff": {
            "kind": "boolean",
            "origin": "registerBit",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "LT register 1 bit 2",
            "events": [
              719,
              819
            ],
            "evidence": "lt.subsystems"
          }
        }
      },
      "ControllerMeasuredValue": {
        "required": [
          "value",
          "unit"
        ],
        "type": "object",
        "properties": {
          "value": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "The scaled value, already in the unit named beside it.",
            "format": "double"
          },
          "unit": {
            "type": "string",
            "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
          }
        },
        "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit.",
        "x-controller-values": {
          "value": {
            "kind": "number",
            "origin": "derived",
            "unit": "modeDependent",
            "unitSource": "the owning measurement's unit source",
            "encoding": "selected by the owning measurement",
            "source": "the owning measurement's value register",
            "events": [ ],
            "evidence": "i1.valve-amount"
          },
          "unit": {
            "kind": "enum",
            "origin": "derived",
            "unit": "modeDependent",
            "unitSource": "the owning measurement's unit source",
            "encoding": "minutes, seconds, cubicMetres, hours or litres",
            "source": "the owning measurement's unit source",
            "events": [ ],
            "evidence": "i1.valve-amount"
          }
        }
      },
      "ControllerMetadataResponse": {
        "type": "object",
        "properties": {
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "note": {
            "type": [
              "null",
              "string"
            ]
          },
          "objectStatus": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerCodedState"
              }
            ]
          },
          "isControlled": {
            "type": [
              "null",
              "boolean"
            ]
          },
          "isGeneratorPresent": {
            "type": [
              "null",
              "boolean"
            ]
          },
          "electricContractNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Identity metadata present for every controller model. `ObjectStatus` is the\nraw RECO object-registry status code from the all-model object view, passed through\nuntranslated; the LT-only real-time `globalStatus` lives in the status group\ninstead."
      },
      "ControllerMonthDay": {
        "required": [
          "month",
          "day"
        ],
        "type": "object",
        "properties": {
          "month": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Calendar month, 1-12 as the device reports it.",
            "format": "int32"
          },
          "day": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Day of that month, as the device reports it.",
            "format": "int32"
          }
        },
        "description": "A calendar day without a year, as the controller configures its summer-time window.\nThe register packs it as day × 100 + month (27 March arrives as 2703); it is split\nhere so no consumer guesses the digit order — live controllers confirm the day-first\npacking, and the reverse reading would produce impossible months.",
        "x-controller-values": {
          "month": {
            "kind": "calendar",
            "origin": "packedRegister",
            "unit": "none",
            "unitSource": "",
            "encoding": "packed % 100",
            "source": "Owning packed day/month register",
            "events": [ ],
            "evidence": "lt.schedule"
          },
          "day": {
            "kind": "calendar",
            "origin": "packedRegister",
            "unit": "none",
            "unitSource": "",
            "encoding": "packed / 100",
            "source": "Owning packed day/month register",
            "events": [ ],
            "evidence": "lt.schedule"
          }
        }
      },
      "ControllerOperatingMode": {
        "enum": [
          "active",
          "inactiveOpen",
          "inactiveClosed"
        ],
        "description": "The master controller's working mode. Neutralizing it is two distinct outcomes, not one\nwith a flag: the master valve is deliberately left open or deliberately left closed, and\nthe device has a separate address for each."
      },
      "ControllerRegisterBitItemResponse": {
        "required": [
          "bit",
          "value",
          "eventNumber",
          "offEventNumber"
        ],
        "type": "object",
        "properties": {
          "bit": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Zero-based bit index (Agam's own documentation counts from one).",
            "format": "int32"
          },
          "value": {
            "type": "boolean"
          },
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The on event number reporting this bit, derived arithmetically for every bit.",
            "format": "int32"
          },
          "offEventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The off twin, always exactly one hundred above the on number.",
            "format": "int32"
          },
          "parameterName": {
            "type": [
              "null",
              "string"
            ]
          },
          "displayLabels": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerEventLabel"
              }
            ]
          }
        },
        "description": "One bit of a digital-zone register: its raw value and the on/off event pair that\nreports it live, named where the catalogue names it."
      },
      "ControllerRegisterItemResponse": {
        "required": [
          "index",
          "value"
        ],
        "type": "object",
        "properties": {
          "index": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "value": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The raw stored value, unscaled and uninterpreted.",
            "format": "int32"
          },
          "kind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The register zone, or `null` for the registers outside every event\nblock (the long layout's trailing clock registers).",
                "$ref": "#/components/schemas/ControllerRegisterKind"
              }
            ]
          },
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The analogue event number reporting this register live; digital registers carry numbers per bit.",
            "format": "int32"
          },
          "parameterName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Confirmed parameter name, when the catalogue names this register for the model."
          },
          "displayLabels": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The reference's own display labels, when it labels this register.",
                "$ref": "#/components/schemas/ControllerEventLabel"
              }
            ]
          },
          "bits": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ControllerRegisterBitItemResponse"
            },
            "description": "The sixteen bits of a digital-zone register, in bit order; absent for analogue zones."
          }
        },
        "description": "One raw register: its value as the store holds it, the zone it sits in, and — where\nthe event directory names it — the analogue event's name and reference labels. Digital\nzones carry their sixteen bits broken out instead."
      },
      "ControllerRegisterKind": {
        "enum": [
          "statusBit",
          "setBit",
          "readOnly",
          "setPoint",
          "accumulator",
          null
        ]
      },
      "ControllerRemainingStateTarget": {
        "enum": [
          "valveAmount",
          "valveFertilizerAmount",
          "valvePulseCount",
          "valvePulseInterval",
          "minutesBetweenIrrigationCycles",
          "rinseTime"
        ],
        "description": "Which running countdown an adjustment overwrites. Closed for the same reason as\nControllerAccumulatorTarget: each member is one register the device counts\ndown, and the only adjustments the reference product actually performs are the two valve\namounts. The rest are named because the registers exist and the configuration surface\nreports them, not because a flow drives them yet."
      },
      "ControllerResyncRequiredResponse": {
        "required": [
          "windowId",
          "reason"
        ],
        "type": "object",
        "properties": {
          "windowId": {
            "type": "string",
            "format": "uuid"
          },
          "reason": {
            "type": "integer"
          }
        }
      },
      "ControllerStateItemResponse": {
        "required": [
          "id"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "globalState": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerGlobalStateResponse"
              }
            ]
          },
          "deviceState": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDeviceStateResponse"
              }
            ]
          }
        },
        "additionalProperties": false,
        "description": "One controller in a state refresh. The default response carries identity and available\nrealtime global state; model-specific details are opt-in."
      },
      "ControllerStatesChangedResponse": {
        "required": [
          "schemaVersion",
          "windowId",
          "sequence",
          "controllers"
        ],
        "type": "object",
        "properties": {
          "schemaVersion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "windowId": {
            "type": "string",
            "format": "uuid"
          },
          "sequence": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "controllers": {
            "type": "array",
            "items": {
              "required": [
                "id"
              ],
              "type": "object",
              "properties": {
                "id": {
                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                  "type": [
                    "integer",
                    "string"
                  ],
                  "format": "int64"
                },
                "metadata": {
                  "required": [
                    "modelCode",
                    "objectStatus"
                  ],
                  "type": "object",
                  "properties": {
                    "modelCode": {
                      "type": "string"
                    },
                    "objectStatus": {
                      "required": [
                        "code"
                      ],
                      "type": "object",
                      "properties": {
                        "code": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The raw value, as its source reports it.",
                          "format": "int32"
                        },
                        "name": {
                          "type": [
                            "null",
                            "string"
                          ],
                          "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                        }
                      },
                      "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                    }
                  }
                },
                "globalState": {
                  "required": [
                    "code",
                    "name",
                    "isConnected"
                  ],
                  "type": "object",
                  "properties": {
                    "code": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "integer",
                        "string"
                      ],
                      "format": "int32"
                    },
                    "name": {
                      "type": "string"
                    },
                    "isConnected": {
                      "type": "boolean"
                    }
                  }
                },
                "registerState": {
                  "type": "object",
                  "properties": {
                    "batteryVoltage": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "currentFlow": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "totalSlavesFlow": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "alarmActive": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "activeValvesCount": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "null",
                        "integer",
                        "string"
                      ],
                      "format": "int32"
                    },
                    "literPerPulse": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "version": {
                      "required": [
                        "value",
                        "kind"
                      ],
                      "type": "object",
                      "properties": {
                        "value": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The register's value, as the controller reports it.",
                          "format": "int32"
                        },
                        "kind": {
                          "enum": [
                            "unspecified",
                            "hardware"
                          ],
                          "description": "            What a controller's version register is a version <em>of</em>.\n            A closed set because it is a RECOM classification of an external fact, not a device code:\nthe models name their version register differently, and this records which naming applies\nrather than letting a consumer guess from the model."
                        }
                      },
                      "description": "            A controller's version register, paired with what it is a version of.\n            The third member of the value-shape family, and it exists for the same reason as the other\ntwo. ControllerMeasuredValue pairs a number with a unit that varies by mode;\nControllerCodedState pairs a code with the name a vocabulary gives it; this pairs a\nversion with its subject, which varies by model. The irrigation controller reports a\nhardware revision here and the master and lighting controllers report an unqualified\nversion number, so a single member name could only be right for one of them."
                    },
                    "isPowerConnected": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "isDoorClosed": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "isSystemDisabled": {
                      "type": [
                        "null",
                        "boolean"
                      ],
                      "description": "The read-only system-disabled status bit (register 0 bit 12, Agam\n`REG:0_BIT13`); `true` is disabled, `false`\nenabled, `null` when the model does not report it. Reported live as\nevents 713 (disabled) and 813 (enabled)."
                    },
                    "isLightOn": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "currentTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "sunriseTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "sunsetTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightOnTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightOffTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightingControl": {
                      "required": [
                        "mainSwitch",
                        "nonEssentialLighting",
                        "essentialLighting",
                        "generatorBackupLighting",
                        "generator",
                        "schedule"
                      ],
                      "type": "object",
                      "properties": {
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The controller's general alarm bit."
                        },
                        "communicationFault": {
                          "type": "boolean",
                          "description": "The controller detects a communication fault (register 0 bit 15) — the same bit DM\nreports under the same name."
                        },
                        "isControlledByLocalClock": {
                          "type": "boolean",
                          "description": "Lighting is switched by the controller's own clock rather than commanded."
                        },
                        "isWaterLevelLow": {
                          "type": "boolean",
                          "description": "Water level below threshold, reported alongside the generator status."
                        },
                        "mainSwitch": {
                          "type": "object",
                          "properties": {
                            "isLocalControl": {
                              "type": "boolean",
                              "description": "Switched to local control at the cabinet."
                            },
                            "isRemoteControl": {
                              "type": "boolean",
                              "description": "Switched to remote control."
                            },
                            "isOff": {
                              "type": "boolean",
                              "description": "Switched off."
                            }
                          },
                          "description": "Main-switch position of an LT controller, as three independent register bits."
                        },
                        "nonEssentialLighting": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The circuit is energised."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The controller reports a fault on this circuit."
                            },
                            "isDisabled": {
                              "type": "boolean",
                              "description": "The circuit is disabled in configuration, so it will not switch on."
                            }
                          },
                          "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags."
                        },
                        "essentialLighting": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The circuit is energised."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The controller reports a fault on this circuit."
                            },
                            "isDisabled": {
                              "type": "boolean",
                              "description": "The circuit is disabled in configuration, so it will not switch on."
                            }
                          },
                          "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags."
                        },
                        "generatorBackupLighting": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The circuit is energised."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The controller reports a fault on this circuit."
                            },
                            "isDisabled": {
                              "type": "boolean",
                              "description": "The circuit is disabled in configuration, so it will not switch on."
                            }
                          },
                          "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags."
                        },
                        "generator": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The generator is running."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The generator reports a fault."
                            },
                            "isMinimumSwitchOn": {
                              "type": "boolean",
                              "description": "The generator's minimum-level switch is engaged."
                            },
                            "hasBatteryChargerError": {
                              "type": "boolean",
                              "description": "The generator's battery charger reports a fault."
                            },
                            "isFuelLevelLow": {
                              "type": "boolean",
                              "description": "Fuel level is below the configured threshold."
                            }
                          },
                          "description": "Standby-generator status of an LT controller, decoded from the generator register.\nIt backs the essential lighting circuits when mains power fails, so its faults are\noperationally urgent even while the lights are still on."
                        },
                        "isCommunicationPowerDetected": {
                          "type": "boolean",
                          "description": "The communication controller's power detection bit."
                        },
                        "isCommunicationBatteryVoltageOk": {
                          "type": "boolean",
                          "description": "The communication controller reports its battery voltage in range."
                        },
                        "schedule": {
                          "type": "object",
                          "properties": {
                            "onsetMinutes": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "Minutes the light-on moment is shifted relative to the computed sunset.",
                              "format": "int32"
                            },
                            "offsetMinutes": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "Minutes the light-off moment is shifted relative to the computed sunrise.",
                              "format": "int32"
                            },
                            "summerTimeStart": {
                              "required": [
                                "month",
                                "day"
                              ],
                              "type": "object",
                              "properties": {
                                "month": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Calendar month, 1-12 as the device reports it.",
                                  "format": "int32"
                                },
                                "day": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Day of that month, as the device reports it.",
                                  "format": "int32"
                                }
                              },
                              "description": "A calendar day without a year, as the controller configures its summer-time window.\nThe register packs it as day × 100 + month (27 March arrives as 2703); it is split\nhere so no consumer guesses the digit order — live controllers confirm the day-first\npacking, and the reverse reading would produce impossible months."
                            },
                            "summerTimeEnd": {
                              "required": [
                                "month",
                                "day"
                              ],
                              "type": "object",
                              "properties": {
                                "month": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Calendar month, 1-12 as the device reports it.",
                                  "format": "int32"
                                },
                                "day": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Day of that month, as the device reports it.",
                                  "format": "int32"
                                }
                              },
                              "description": "A calendar day without a year, as the controller configures its summer-time window.\nThe register packs it as day × 100 + month (27 March arrives as 2703); it is split\nhere so no consumer guesses the digit order — live controllers confirm the day-first\npacking, and the reverse reading would produce impossible months."
                            },
                            "doorStatusThresholdTime": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "How long a door state must persist before the controller reports it, in device\ntime units — no available source names the unit, so it is not guessed.",
                              "format": "int32"
                            },
                            "lightStatusThresholdTime": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "How long a light state must persist before the controller reports it, in the same\nunnamed device time units.",
                              "format": "int32"
                            }
                          },
                          "description": "Configured lighting schedule of an LT controller: the offsets and thresholds that\ndecide when the controller switches its circuits, read back exactly as configured."
                        }
                      },
                      "description": "Everything an LT (street-lighting) controller reports beyond the values every model\nshares. Present only for LT controllers on the 1066-register layout; other models and\nthe short layout leave it `null`."
                    },
                    "damControl": {
                      "type": "object",
                      "properties": {
                        "isolationFault": {
                          "type": "boolean",
                          "description": "Isolation fault on the cabinet supply (register 0 bit 2)."
                        },
                        "chargeRelayFault": {
                          "type": "boolean",
                          "description": "Battery charge relay fault (register 0 bit 3)."
                        },
                        "dcConverterFault": {
                          "type": "boolean",
                          "description": "DC converter fault (register 0 bit 4)."
                        },
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The general-alarm status bit (register 0 bit 14), at the same bit as on the\nlighting and irrigation controllers."
                        },
                        "communicationFault": {
                          "type": "boolean",
                          "description": "Communication fault with the cabinet (register 0 bit 15)."
                        },
                        "isCommunicationPowerDetected": {
                          "type": "boolean",
                          "description": "The communication controller reports mains power present (register 36 bit 1)."
                        },
                        "isCommunicationBatteryVoltageOk": {
                          "type": "boolean",
                          "description": "The communication controller reports its battery voltage in range (register 36\nbit 3)."
                        },
                        "clearAlarmsCommand": {
                          "type": "boolean",
                          "description": "State of the clear-alarms command latch; RECOM never sets it."
                        },
                        "configuredDamCount": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Dam count the controller is configured for. `dams` always carries the\nfour the register map covers: trimming to this value would hide a dam reporting\nstate after someone lowered the configured count, which is a fault worth seeing.",
                          "format": "int32"
                        },
                        "communicationFlag": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Vendor communication flag, reported raw.",
                          "format": "int32"
                        },
                        "totalAccumulation": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The controller's accumulating total (register 846), in the device's own\naccumulator units — no source confirms a scale, so the value stays raw rather\nthan guess one.",
                          "format": "int32"
                        },
                        "dams": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "number": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "One-based dam number, as the controller labels it.",
                                "format": "int32"
                              },
                              "isOpen": {
                                "type": "boolean",
                                "description": "The dam is fully open (status register bit 0)."
                              },
                              "isClosed": {
                                "type": "boolean",
                                "description": "The dam is fully closed (status register bit 1)."
                              },
                              "isMoving": {
                                "type": "boolean",
                                "description": "The dam is travelling between its end positions (status register bit 2)."
                              },
                              "isOk": {
                                "type": "boolean",
                                "description": "The dam reports no fault (status register bit 3)."
                              },
                              "hasFeedbackFault": {
                                "type": "boolean",
                                "description": "The dam's position feedback disagrees with its drive (status register bit 15)."
                              },
                              "isControlEnabled": {
                                "type": "boolean",
                                "description": "True when the dam accepts remote open/close commands."
                              },
                              "openCommand": {
                                "type": "boolean",
                                "description": "State of the open command latch. RECOM issues no controller commands; this reports\nwhat the controller currently holds, whoever set it."
                              },
                              "closeCommand": {
                                "type": "boolean",
                                "description": "State of the close command latch; see `openCommand`."
                              }
                            },
                            "description": "One dam of a `DM` controller: where its gate is, whether the feedback agrees, and\nwhether remote control over it is enabled."
                          },
                          "description": "The four dams, in controller order."
                        }
                      },
                      "description": "`DM`-only subsystem detail: cabinet faults, the communication controller, and the\n        four dam gates. Null for every other model and for the short layout."
                    },
                    "irrigation": {
                      "required": [
                        "dayOfWeek",
                        "totalFertilizerLeak"
                      ],
                      "type": "object",
                      "properties": {
                        "clockMinutesFromMidnight": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Controller clock in minutes from midnight. Not the `HHmm` encoding the lighting\nclock uses: the irrigation register genuinely holds minutes, and normalising the two\ninto one field would make a wrong reading indistinguishable from a right one.",
                          "format": "int32"
                        },
                        "dayOfWeek": {
                          "required": [
                            "code"
                          ],
                          "type": "object",
                          "properties": {
                            "code": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "description": "The raw value, as its source reports it.",
                              "format": "int32"
                            },
                            "name": {
                              "type": [
                                "null",
                                "string"
                              ],
                              "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                            }
                          },
                          "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                        },
                        "hasMainValve": {
                          "type": "boolean",
                          "description": "Whether a main valve is fitted: bit 0 of the setup register (17 on the\n548-register layout, 43 on the 1066-register one), which the reference names\n\"Master Valve Exists\". It is also what decides the main valve's port number,\nsince a fitted main valve occupies the last hardware port."
                        },
                        "hardwarePortCount": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "            How many valve ports the controller board has (register 40 on the 548-register\n            layout, 66 on the 1066-register one; reported as analogue event 1713).\n            This is the fact that says which port number the special valves occupy: the\nmain valve is the last port when one is fitted, and the filter valve sits below it,\nbelow the fertilizer valve again when that is fitted too. A command addressed at the\nmain valve without it would either guess a port or refuse to run.",
                          "format": "int32"
                        },
                        "hasFilter": {
                          "type": "boolean",
                          "description": "Whether a filter is fitted (register 42 short, 68 long; analogue event 1715). The\ndevice reports this as a whole register rather than a status bit, so any non-zero\nvalue means fitted."
                        },
                        "filterCount": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How many filters the controller rinses (register 390 short, 761 long; event 2515).\nZero when `hasFilter` is false.",
                          "format": "int32"
                        },
                        "hasFertilizerValve": {
                          "type": "boolean",
                          "description": "Whether a fertilizer valve is fitted: bit 1 of the setup register (17 short, 43\nlong), \"Compost Exists\" in the reference."
                        },
                        "supportsPulses": {
                          "type": "boolean",
                          "description": "Whether pulse irrigation is supported: bit 2 of the setup register (17 short, 43\nlong), \"Allow Pulse Watering\" in the reference."
                        },
                        "isFertilizerByTime": {
                          "type": "boolean",
                          "description": "Whether the controller doses fertilizer by time rather than by quantity (setup\nregister bit 6). It is what decides whether a valve's fertilizer accumulator counts\nhours or litres, so it is published as a fact of its own rather than only as the unit\nbeside that value."
                        },
                        "isFertilizerProportional": {
                          "type": "boolean",
                          "description": "Whether fertilizer is dosed in proportion to the water flowing (setup register bit 7)\nrather than as a fixed amount."
                        },
                        "isRinsingBlockedDuringPipeFill": {
                          "type": "boolean",
                          "description": "Whether the controller refuses to start a filter rinse while pipes are still filling\n(setup register bit 5)."
                        },
                        "isWaterMeterInputOn": {
                          "type": "boolean",
                          "description": "The water meter's input line as the controller last read it: register 2 bit 0,\nreported on by event 733 and off by 833. A live contact, not a presence flag — the\ncontroller re-reports it about once a second while water moves, which the legacy\nUI shows as a pulse indicator on the main valve. Whether a meter is fitted at all\nis `supportsPulses`. A state refresh holds the value at the snapshot; the hub\nwindow carries it as it moves."
                        },
                        "isFertilizerMeterInputOn": {
                          "type": "boolean",
                          "description": "The fertilizer meter's input line (register 2 bit 1; events 734/834). Live, as the water meter's is."
                        },
                        "isPressureMeterInputOn": {
                          "type": "boolean",
                          "description": "The pressure meter's input line (register 2 bit 2; events 735/835)."
                        },
                        "isPressureDifferentialMeterInputOn": {
                          "type": "boolean",
                          "description": "The differential-pressure meter's input line (register 2 bit 3; events 736/836)."
                        },
                        "controllerAddress": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The controller's own network address (read-only register 39 short, 65 long), the\nsame fact the catalogue already names `controllerAddress` at event 1712.",
                          "format": "int32"
                        },
                        "irrigatingValveNumber": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Number of the valve the controller reports as irrigating now (read-only register 37\nshort, 63 long; event 1710, \"the valve now irrigating\"). Both mapping files name it\n`RO_ActualIrrigationValve`; what the register holds while nothing irrigates is\nstated by no source, so the value is published raw rather than turned into a null.",
                          "format": "int32"
                        },
                        "filterWashBehaviour": {
                          "enum": [
                            "stopIrrigationAndFertilization",
                            "continueIrrigationAndFertilization",
                            "stopFertilizationOnly",
                            "unused"
                          ],
                          "description": "What an I1 controller keeps running while its filter washes, read from bits 0 and 1 of\nthe behaviour register (18 short / 44 long; events 1533/1633 and 1534/1634 respectively)."
                        },
                        "highFlowBehaviour": {
                          "enum": [
                            "closeValveWithAutomaticReset",
                            "closeAndDisableValveWithManualReset",
                            "pauseProgramWithAutomaticReset",
                            "pauseProgramDisableValveWithAutomaticProgramReset"
                          ],
                          "description": "What an I1 controller does when a running program reports a high flow, read from the two\nbits that decide it together: the behaviour register's bit 5 (18 short / 44 long, events\n1538/1638) chooses between closing the offending valve and pausing the whole program, and\nbit 2 of register 393 (764 long, event 2518) chooses between an automatic reset and one a\nperson has to perform."
                        },
                        "continuesIrrigationOnFertilizerFault": {
                          "type": "boolean",
                          "description": "Whether irrigation carries on when the fertilizer system faults (behaviour register\n18 short / 44 long, bit 2; events 1535/1635)."
                        },
                        "opensMainValveBeforeValves": {
                          "type": "boolean",
                          "description": "Whether the main valve opens before the valves it feeds (behaviour register 18\nshort / 44 long, bit 3; events 1536/1636)."
                        },
                        "opensMainValveAfterValves": {
                          "type": "boolean",
                          "description": "Whether the main valve opens after the valves it feeds (behaviour register 18\nshort / 44 long, bit 4; events 1537/1637). The companion of\n`opensMainValveBeforeValves`: the device carries the two orderings as\nseparate bits, so they are published as the two facts it reports."
                        },
                        "allowsValveGrouping": {
                          "type": "boolean",
                          "description": "Whether a valve may open alongside other valves rather than only on its own\n(behaviour register 18 short / 44 long, bit 7; events 1540/1640)."
                        },
                        "isExternalPowerConnected": {
                          "type": "boolean",
                          "description": "Whether external power is connected (register 15 bit 1; events 1150/1250). The\nregister sits in the status zone, so the index is the same on both layouts."
                        },
                        "isCharging": {
                          "type": "boolean",
                          "description": "Whether the controller is charging (register 15 bit 4; events 1153/1253)."
                        },
                        "externalPowerVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "External power supply voltage (register 29 short, 55 long; event 1702), stored in\ntenths of a volt exactly as the battery voltage beside it is.",
                          "format": "double"
                        },
                        "autoNominalFlowChangePercent": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Percentage change applied to the nominal flow in automatic mode (register 80 on\nthe short layout, 451 on the long one).",
                          "format": "int32"
                        },
                        "mainValveDelaySeconds": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Delay before the main valve acts, in seconds (register 377 short, 748 long).",
                          "format": "int32"
                        },
                        "valveOpenVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "null",
                            "number",
                            "string"
                          ],
                          "description": "Solenoid drive voltage in volts — the low byte of the packed valve-drive register\n(79, short layout only), stored in tenths of a volt. Null on the long layout, whose\nequivalent register is unconfirmed. Same fact and name as the IP master's value.",
                          "format": "double"
                        },
                        "valveOpenTimeMs": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "null",
                            "integer",
                            "string"
                          ],
                          "description": "Solenoid drive time in milliseconds — the high byte of the same packed register.",
                          "format": "int32"
                        },
                        "currentFlow": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Current water flow in m³/h — a 32-bit LSW/MSW register pair joined here and scaled\nby the reference's ÷100, so consumers never see the 16-bit seam (registers 30/31 on\nthe short layout, 56/57 on the long one).",
                          "format": "double"
                        },
                        "fertilizerFlow": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Current fertilizer flow in cm³/h (registers 32/33 short, 58/59 long). Scaled by the\nfertilizer meter's own volume per pulse — `cubicCentimetrePerPulse` —\nnot by the water meter's litres multiplier, which is what the water flow beside it\nuses.",
                          "format": "double"
                        },
                        "totalIrrigation": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Accumulated irrigation total in cubic metres (registers 475/476 short, 846/847 long;\nLSW/MSW joined).",
                          "format": "int64"
                        },
                        "totalWaterLeak": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Accumulated water-leak total in cubic metres (registers 477/478 short, 848/849 long).",
                          "format": "int64"
                        },
                        "totalFertilizerLeak": {
                          "required": [
                            "value",
                            "unit"
                          ],
                          "type": "object",
                          "properties": {
                            "value": {
                              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                              "type": [
                                "number",
                                "string"
                              ],
                              "description": "The scaled value, already in the unit named beside it.",
                              "format": "double"
                            },
                            "unit": {
                              "type": "string",
                              "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                            }
                          },
                          "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                        },
                        "totalRinses": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Count of filter rinses performed (register 482 short, 853 long).",
                          "format": "int32"
                        },
                        "remainingMinutesBetweenRinseCycles": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Minutes left until the next rinse cycle (register 277 short, 648 long).",
                          "format": "int32"
                        },
                        "remainingMinutesBetweenRinseValves": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Minutes left before the rinse moves to its next valve (register 278 short, 649\nlong).",
                          "format": "int32"
                        },
                        "remainingRinseTime": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Time left in the running rinse (register 279 short, 650 long). A device time value\nwhose stored resolution no source names, so it is published raw rather than\nguessed.",
                          "format": "int32"
                        },
                        "rinseCyclesWithoutSuccess": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Count of rinse cycles that did not complete (register 376 short, 747 long).",
                          "format": "int32"
                        },
                        "timeBetweenRinsesMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Configured minutes between rinses (register 382 short, 753 long) — counted against\nactual irrigation minutes, not the wall clock.",
                          "format": "int32"
                        },
                        "rinseTimeBetweenValves": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Configured rinse hand-over time from valve to valve, in seconds (register 383 short,\n754 long).",
                          "format": "int32"
                        },
                        "rinseDurationSeconds": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Configured duration of one rinse, in seconds (register 384 short, 755 long).",
                          "format": "int32"
                        },
                        "cubicCentimetrePerPulse": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Cubic centimetres one fertilizer-meter pulse stands for (register 379 short, 750\nlong; event 2504), the fertilizer twin of the controller's water litres-per-pulse.\nIt is also the scale `fertilizerFlow` is computed with, which is why the\nmember is named for the unit it carries rather than for the ratio it expresses.",
                          "format": "int32"
                        },
                        "noIrrigationTime": {
                          "type": "string",
                          "description": "The configured no-irrigation window (register 381 short, 752 long; event 2506, \"a\ntime when watering is not allowed\"), stored as minutes from midnight and published\nas `HH:mm` — the same rendering the lighting clocks get, and the same one the\nevent carries."
                        },
                        "noPulsesAlarmDelayMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How long the controller waits, in minutes, before it raises a no-pulses alarm\n(register 276 short, 647 long; event 2399).",
                          "format": "int32"
                        },
                        "uncontrolledFlowAlarmPulses": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How many pulses the controller counts before it reports an uncontrolled flow\n(register 386 short, 757 long; event 2511).",
                          "format": "int32"
                        },
                        "valvesMeteringWaterOnTimedIrrigation": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Numbers of the valves that meter water while irrigating by time (register 394 short,\n765 long; event 2519, \"measuring water when working by time\"). One bit per valve, as\nthe legacy handler reads it."
                        },
                        "openValves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Numbers of the valves the controller reports as open, whether a program or a person\nopened them (register 1 bits 0-12, valves 1-13, events 717-729). The companion of\n`manuallyOpenedValves`, which narrows that to the hand-opened ones."
                        },
                        "isRinseValveOpen": {
                          "type": "boolean",
                          "description": "Whether the rinse valve is open (register 1 bit 13)."
                        },
                        "manuallyOpenedValves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Numbers of the valves reported as opened manually (register 3 bits 0-12, valves\n1-13 — the register spends its three remaining bits on the rinse, fertilizer and\nmain valves below, so only thirteen numbered valves can carry the flag)."
                        },
                        "valveFaults": {
                          "type": "object",
                          "properties": {
                            "chainingProblem": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a chaining/sequence problem (register 4, events 765-780)."
                            },
                            "highFlowAlarm": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a high-flow alarm (register 5, events 781-796). The controller\nfirmware names it `CRC_REG__ALARM_FLOW_HI_BMP__005` and documents exactly those\nevents, with off twins 881-896."
                            },
                            "lowFlowAlarm": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a low-flow alarm (register 6, events 901-916)."
                            },
                            "fertilizerMissing": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting missing fertilizer material (register 7, events 917-932)."
                            },
                            "stoppedOnTimeLimit": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves the controller stopped because they reached their time limit (register 8,\nevents 933-948)."
                            },
                            "fertilizerLeak": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a leak in the fertilization system (register 9, events 949-964).\nThe per-valve companion of the controller-wide `hasFertilizerLeak` bit."
                            },
                            "stoppedOnLowPressure": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves the controller stopped for lack of pressure (register 10, events 965-980).\nThe per-valve companion of the controller-wide `isStoppedOnLowPressure` bit."
                            },
                            "frozen": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves held frozen (register 11, events 981-996) — the per-valve companion of the\ncontroller-wide `isFrozen` bit."
                            },
                            "fertilizerDelayed": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves whose fertilization is delayed by the cyclic rule (register 12, events\n1101-1116)."
                            },
                            "irrigatedWithoutFertilizer": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves that irrigated on without their fertilizer (register 13, events 1117-1132).\nDistinct from `fertilizerMissing`: this one says the controller carried on\nregardless."
                            },
                            "noPulses": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting no water-meter pulses (register 14, events 1133-1148)."
                            }
                          },
                          "description": "The irrigation controller's per-valve fault bitmaps: registers 4-14, eleven registers of\nthe status zone that each spend one bit per valve on one kind of fault. A set bit means\nthat valve is currently in that fault; the device raises the on event when it sets and\nthe off twin when it clears."
                        },
                        "isRinseOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the rinse valve was opened manually (register 3 bit 13)."
                        },
                        "isFertilizerValveOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the fertilizer valve was opened manually (register 3 bit 14)."
                        },
                        "isMainValveOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the main valve was opened manually (register 3 bit 15)."
                        },
                        "isRinsing": {
                          "type": "boolean",
                          "description": "Whether the filter is rinsing right now (register 0 bit 0)."
                        },
                        "isWaitingForRinsingMode": {
                          "type": "boolean",
                          "description": "Whether the controller is waiting to enter rinsing mode (register 0 bit 1)."
                        },
                        "isInRinsingCycle": {
                          "type": "boolean",
                          "description": "Whether the controller is currently within a rinsing cycle (register 0 bit 2)."
                        },
                        "isMainValveOpen": {
                          "type": "boolean",
                          "description": "Whether the main valve is open (register 0 bit 3)."
                        },
                        "isInRinsingTransition": {
                          "type": "boolean",
                          "description": "Whether the controller is transitioning between rinsing states (register 0 bit 4)."
                        },
                        "hasWaterLeak": {
                          "type": "boolean",
                          "description": "Whether a systemic water leak is detected (register 0 bit 5)."
                        },
                        "hasFertilizerLeak": {
                          "type": "boolean",
                          "description": "Whether a leak in the fertilization system is detected (register 0 bit 6)."
                        },
                        "isLowInputPressure": {
                          "type": "boolean",
                          "description": "Whether input pressure is missing (register 0 bit 7)."
                        },
                        "isProgramModeWithoutIrrigation": {
                          "type": "boolean",
                          "description": "Whether program mode is active without irrigation (register 0 bit 8). This is the\ndevice's reported fact; it is not inverted into a derived running-state flag."
                        },
                        "isFertilizerValveOpen": {
                          "type": "boolean",
                          "description": "Whether the fertilizer valve is open (register 0 bit 9)."
                        },
                        "isStoppedOnLowPressure": {
                          "type": "boolean",
                          "description": "Whether the system stopped itself on low pressure (register 0 bit 11)."
                        },
                        "isFrozen": {
                          "type": "boolean",
                          "description": "Whether the system is frozen (register 0 bit 10) — the old firmware's\ndisable flag, kept by newer firmware beside the system-disabled bit. The legacy\nconsumer treated frozen-or-disabled as one fact; both are published separately so\nnothing is derived."
                        },
                        "isIrrigatingOrRinsing": {
                          "type": "boolean",
                          "description": "Whether the system is irrigating or rinsing (register 0 bit 13 — the device reports\nthe two as one fact, so they are not split here)."
                        },
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The general-alarm status bit (register 0 bit 14), as on LT and DM."
                        },
                        "isLowVoltage": {
                          "type": "boolean",
                          "description": "Whether the supply voltage is low (register 0 bit 15)."
                        },
                        "valves": {
                          "type": "array",
                          "items": {
                            "required": [
                              "amount",
                              "amountLeft",
                              "amountBeforeFertilizing",
                              "amountAfterFertilizing",
                              "fertilizerAmount",
                              "fertilizerAmountLeft",
                              "totalFertilizer"
                            ],
                            "type": "object",
                            "properties": {
                              "number": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "One-based valve number, as the controller labels it. Not a register of its own: it\nis the slot the valve occupies, and every per-valve register below is read at its\nbase index plus this number minus one.",
                                "format": "int32"
                              },
                              "isActive": {
                                "type": "boolean",
                                "description": "True when the valve is within the controller's active-valve count. Valves past it\nstill hold register values, but the controller does not run them."
                              },
                              "isDisabled": {
                                "type": "boolean",
                                "description": "Whether the valve is disabled in configuration, so the controller will not run\nit. One bit per valve in a single register (392), the valve's own number\nselecting the bit, counting from zero. The long layout stores the same bitmap\nat 763, but carries no valve list to hang it on."
                              },
                              "amount": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "amountLeft": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "amountBeforeFertilizing": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "amountAfterFertilizing": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "cycleDays": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Length of this valve's irrigation cycle in days (register 228 plus the valve slot,\nevents 2351-2366), the interval the weekday list does not express.",
                                "format": "int32"
                              },
                              "cycleDaysLeft": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Days left until this valve's cycle completes (register 146 plus the valve slot,\nevents 1868-1883).",
                                "format": "int32"
                              },
                              "fertilizerAmount": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "fertilizerAmountLeft": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "totalIrrigation": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Everything this valve has irrigated since the accumulator was last reset (registers\n484/485 plus twice the valve slot, joined low word first). Cubic metres: the shipped\nclient's accumulator table heads the column with the unit and applies no scaling to\nthe joined value.",
                                "format": "int64"
                              },
                              "totalFertilizer": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "pulseCount": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "How many irrigation pulses the valve runs (register 395 plus the valve slot;\ndevice events 2520-2535). Read on the 548-register layout only, like the rest\nof the valve block.",
                                "format": "int32"
                              },
                              "pulseIntervalMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Minutes between those pulses (register 411 plus the valve slot; device events\n2536-2551). Read on the 548-register layout only.",
                                "format": "int32"
                              },
                              "pulseCountLeft": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "How many of those pulses are still to run (register 82 plus the valve slot; device\nevents 1804-1819) — the running counterpart of `pulseCount`. Both mapping\nfiles name it `SP_NumSplashCyclesRemainValve_N`; the legacy handler reads it raw.",
                                "format": "int32"
                              },
                              "pulseIntervalLeft": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Minutes until the next pulse (register 98 plus the valve slot; device events\n1820-1835), the running counterpart of `pulseIntervalMinutes` and stored in the\nsame unit. The mapping files' variable name says days\n(`SP_NumDaysNextSplashValve_N`); the register documentation names minutes, which\nis also what the set point it counts down from is in.",
                                "format": "int32"
                              },
                              "irrigationFactorPercent": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Per-program irrigation-change percentage applied to every amount (register 459 plus\nthe valve slot). Every non-`with` valve of a program must agree on it; a\ndisagreement is reported as a configuration error.",
                                "format": "int32"
                              },
                              "flowMinimum": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "Configured minimum flow in m³/h (the register holds hundredths).",
                                "format": "double"
                              },
                              "flowNominal": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "Configured nominal flow in m³/h (the register holds hundredths).",
                                "format": "double"
                              },
                              "flowMaximum": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "Configured maximum flow in m³/h (the register holds hundredths).",
                                "format": "double"
                              },
                              "lastFlow": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "The last flow the controller calculated for this valve, in m³/h. The register\nholds tenths — unlike the three configured flows above, which hold hundredths —\nbecause that is how both legacy readers of it divide (see the evidence row).",
                                "format": "double"
                              },
                              "lowFlowAlarmDelayMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Delay in minutes before the low-flow alarm raises (register 427 plus the valve\nslot) — a duration, not a flow threshold.",
                                "format": "int32"
                              },
                              "highFlowAlarmDelayMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Delay in minutes before the high-flow alarm raises (register 443 plus the valve\nslot).",
                                "format": "int32"
                              },
                              "fillTimeMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Pipe fill time for this valve, in minutes — how long the line takes to pressurise\nbefore flow measurement is meaningful.",
                                "format": "int32"
                              },
                              "startTimeMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Program start, in minutes from midnight (register 260 plus the valve slot).\nMeaningful only for a first valve.",
                                "format": "int32"
                              },
                              "startTime": {
                                "type": "string",
                                "description": "The same program start as a time of day, `HH:mm` (600 minutes is\n`10:00`). Rendered beside `startTimeMinutes` rather than instead\nof it: the minutes stay the sortable number, and this is what a screen shows.\nRendered once here, as `noIrrigationTime` is, so REST and the hub cannot\nspell one register two ways. Like the minutes, meaningful only for a first valve."
                              },
                              "startWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the valve irrigates on — bits 0-6 of the weekly-schedule register (244\nplus the valve slot; events 2367-2382), as Sunday-first coded pairs (`1` =\n`sunday` … `7` = `saturday`); empty when the valve does not start a\nprogram of its own. The same register's high byte carries\n`fertilizationWeekDays`."
                              },
                              "fertilizationWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the valve fertilizes on — bits 8-14 of the same weekly-schedule\nregister, in the same Sunday-first vocabulary. Bits 7 and 15 are reserved. A valve\nwhose register holds the reserved \"scheduled by another valve\" value reports no\nfertilization days rather than all seven, for the reason its start days are empty."
                              },
                              "startDayRegister": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Raw weekly-schedule register. Kept alongside the two decoded day lists because the\nweekday bits alone cannot express the reserved value that marks a valve as scheduled\nby another one — decoding it would show a valve starting every day when it starts\non none.",
                                "format": "int32"
                              },
                              "startAfterValve": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Valve number this one follows (register 280 plus the valve slot), or 0 when it\nstarts on its own schedule.",
                                "format": "int32"
                              },
                              "startWithValves": {
                                "type": "array",
                                "items": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "format": "int32"
                                },
                                "description": "Valve numbers that open together with this one, from the bitmap at register 296 plus\nthe valve slot — one bit per valve, counting from zero."
                              },
                              "role": {
                                "enum": [
                                  "unassigned",
                                  "first",
                                  "next",
                                  "with"
                                ],
                                "description": "The part a valve plays in the programs decoded from a controller's registers. Derived,\nnot stored: the controller records start days, a predecessor and a \"start with\" mask,\nand the role follows from them."
                              }
                            },
                            "description": "One irrigation valve of an `I1` controller: its configured amount, its flow\nenvelope, and how it is scheduled relative to the other valves."
                          },
                          "description": "The configured valves, in valve order, read from the per-valve register runs of the\n548-register layout. Empty on the 1066-register layout, which stores the same runs\nbut carries no valve list to hang them on."
                        },
                        "programs": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "number": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Sequence number in discovery order (by valve number), one-based.",
                                "format": "int32"
                              },
                              "startTimeMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Start, in minutes from midnight.",
                                "format": "int32"
                              },
                              "startTime": {
                                "type": "string",
                                "description": "The same start as a time of day, `HH:mm`, copied from the first valve's\n`startTime` so a program and the valve that starts it never disagree."
                              },
                              "startWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the program starts on, as Sunday-first coded pairs (`1` =\n`sunday` … `7` = `saturday` — the day-of-week vocabulary)."
                              },
                              "fertilizationWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the program fertilizes on, from the high byte of the same first-valve\nregister its start days come from; the same Sunday-first vocabulary."
                              },
                              "factorPercent": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "The irrigation-change percentage the program runs at, taken from its valves'\nown factor registers (459 plus the valve slot). Not a register of the program's\nown: a program is reconstructed from its valves, and every non-companion valve\nin one must agree on this number — a disagreement is reported as a\nconfiguration error rather than silently resolved.",
                                "format": "int32"
                              },
                              "valveNumbers": {
                                "type": "array",
                                "items": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "format": "int32"
                                },
                                "description": "Valve numbers in run order: each chained valve followed by the valves that open\nwith it."
                              }
                            },
                            "description": "One irrigation program: a chain of valves that starts together, on the days and at the\ntime its first valve is configured for."
                          },
                          "description": "Programs reconstructed from the valves, earliest start first."
                        },
                        "configurationErrors": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What did not add up while reconstructing the programs — a valve claimed twice, a\nfactor that disagrees with its program, a start-with pointing at itself. Reported\nrather than thrown: an inconsistent controller still has readable state, and hiding\nthe inconsistency is what makes it hard to find."
                        }
                      },
                      "description": "`I1`-only subsystem detail: the controller clock, whether a main valve is fitted,\n        and — on the short layout, the only one that carries the valve configuration registers —\n        the valves and the programs reconstructed from them."
                    },
                    "irrigationMaster": {
                      "required": [
                        "status",
                        "leakageControlMode"
                      ],
                      "type": "object",
                      "properties": {
                        "hasFlowmeter": {
                          "type": "boolean",
                          "description": "Whether a flowmeter is fitted (setup register 43 bit 0)."
                        },
                        "hasMainValve": {
                          "type": "boolean",
                          "description": "Whether a main valve is fitted (setup register 43 bit 1)."
                        },
                        "calculatesFlow": {
                          "type": "boolean",
                          "description": "Whether the master computes flow rather than only measuring it (setup register\n43 bit 2)."
                        },
                        "hasPump1": {
                          "type": "boolean",
                          "description": "Whether the first pump is fitted (setup register 43 bit 3)."
                        },
                        "hasPump2": {
                          "type": "boolean",
                          "description": "Whether the second pump is fitted (setup register 43 bit 5 — bit 4 belongs to\nneither pump, so the two are not adjacent)."
                        },
                        "isMasterValveOpen": {
                          "type": "boolean",
                          "description": "Whether the master valve is open (register 0 bit 0)."
                        },
                        "isMasterValveOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the master valve was opened manually (register 0 bit 3)."
                        },
                        "hasFlowAlarmByMeasure": {
                          "type": "boolean",
                          "description": "Whether a flow alarm raised from measurement is active (register 0 bit 4)."
                        },
                        "hasFlowAlarmWithoutMeasure": {
                          "type": "boolean",
                          "description": "Whether a flow alarm raised without measurement is active (register 0 bit 5)."
                        },
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The general-alarm status bit (register 0 bit 7), as on LT, DM and I1."
                        },
                        "batteryStatusCode": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Raw battery-status code (register 55). A plain code, not a\nControllerCodedState: no source confirms a vocabulary for it, and a\npermanently null name would be noise. Labels are client-owned, as with every other\npublished code.",
                          "format": "int32"
                        },
                        "status": {
                          "required": [
                            "code"
                          ],
                          "type": "object",
                          "properties": {
                            "code": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "description": "The raw value, as its source reports it.",
                              "format": "int32"
                            },
                            "name": {
                              "type": [
                                "null",
                                "string"
                              ],
                              "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                            }
                          },
                          "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                        },
                        "leakageControlMode": {
                          "required": [
                            "code"
                          ],
                          "type": "object",
                          "properties": {
                            "code": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "description": "The raw value, as its source reports it.",
                              "format": "int32"
                            },
                            "name": {
                              "type": [
                                "null",
                                "string"
                              ],
                              "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                            }
                          },
                          "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                        },
                        "litresPerPulse": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "null",
                            "integer",
                            "string"
                          ],
                          "description": "Litres a flowmeter pulse represents. The register holds a decade code (1, 10, 100,\n1000) which is resolved here, so the value is litres and not a code to look up.\nNull when the register holds none of the four known codes.",
                          "format": "int32"
                        },
                        "leakDetectionMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Leak-detection window in minutes (the reference register is named in minutes).",
                          "format": "int32"
                        },
                        "leakDetectionPercent": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How far past the expected flow counts as a leak, as a percentage (register 454).",
                          "format": "int32"
                        },
                        "uncontrolledFlowDetectionTime": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Uncontrolled-flow detection window, in device time units no source names.",
                          "format": "int32"
                        },
                        "uncontrolledFlowDetectionPulses": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How many flowmeter pulses with no valve open raise uncontrolled flow\n(register 456).",
                          "format": "int32"
                        },
                        "closeValveDelaySeconds": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Seconds the master waits before rejecting a close (named in seconds by the reference).",
                          "format": "int32"
                        },
                        "valveOpenVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Solenoid open drive voltage in volts (register 458, stored in tenths of a volt).\nSame fact and name as the irrigation controller's value.",
                          "format": "double"
                        },
                        "valveOpenTimeMs": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Solenoid open drive time in milliseconds (named in ms by the reference).",
                          "format": "int32"
                        },
                        "valveCloseVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Solenoid close drive voltage in volts (register 460, tenths of a volt).",
                          "format": "double"
                        },
                        "valveCloseTimeMs": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Solenoid close drive time in milliseconds (named in ms by the reference).",
                          "format": "int32"
                        },
                        "manualOpenMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How long a manual pump or valve activation runs, in minutes (register 462).",
                          "format": "int32"
                        },
                        "mainValveSlaves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Slave numbers (1-32) that irrigate through this master's main valve."
                        },
                        "pump1Slaves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Slave numbers (1-32) that draw through the first pump — two registers from 604,\nlow word first. The device stores these inverted, so a clear bit means the\nslave uses the pump; the inversion is undone in the register map so no consumer\nrepeats it."
                        },
                        "pump2Slaves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Slave numbers (1-32) that draw through the second pump — two registers from 606,\ninverted the same way."
                        }
                      },
                      "description": "`IP`-only subsystem detail: which hardware the master has, how it handles leaks,\n        how its valves are driven, and which slaves share its main valve and pumps. Null for\n        every other model and for the short layout, which reports none of it."
                    },
                    "weatherStation": {
                      "type": "object",
                      "properties": {
                        "barometer": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Barometric pressure in mmHg (register 57, thousandths of inHg × 25.4 ÷ 1000).",
                          "format": "double"
                        },
                        "outsideTemperature": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Outside temperature in °C (register 60, tenths of °F).",
                          "format": "double"
                        },
                        "windSpeed": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Wind speed in km/h (register 61, mph × 1.609344).",
                          "format": "double"
                        },
                        "windSpeed10MinuteAverage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Ten-minute average wind speed in km/h (register 62, tenths of mph).",
                          "format": "double"
                        },
                        "outsideHumidity": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Outside relative humidity in percent (register 79, raw).",
                          "format": "int32"
                        },
                        "rainRate": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Rain rate in mm/h (register 87, 0.254 mm collector clicks).",
                          "format": "double"
                        },
                        "dayRain": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Rain accumulated today in mm (register 92, 0.254 mm collector clicks).",
                          "format": "double"
                        },
                        "dayEvaporation": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Evapotranspiration accumulated today in mm (register 95, thousandths of an inch).",
                          "format": "double"
                        },
                        "consoleBatteryVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Console battery voltage (register 122, Davis encoding raw × 300 ÷ 512 ÷ 100).\nReplaces the register-62 value this model briefly published as a battery: two\nreference artifacts and live snapshots agree register 62 is the ten-minute average\nwind speed, now published under that fact's own name above.",
                          "format": "double"
                        }
                      },
                      "description": "`WE`-only subsystem detail: the Davis weather-station LOOP measurements the long\n        layout mirrors into registers 54-126. Null for every other model and for the short\n        layout, whose weather registers carry placeholders only."
                    },
                    "syncedAtUtc": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ControllerStateScope": {
        "enum": [
          "explicit",
          "authorized"
        ],
        "description": "How a state refresh chooses its controllers, serialized as a lowercase string like every\nother REST enum. An unrecognized value fails JSON binding as `request.malformed`, so\nthe contract is closed by construction.\nThe live hub asks the same question with ControllerWindowScope and the same two\nanswers, but not in the same words: hub enums cross as numbers, so \"everything I may see\"\nis \"authorized\" here and 1 there. The shapes differ because the converter\nthat makes REST enums strings is registered on the HTTP serializer alone — declaring it on\na type the hub also publishes would silently change the hub's contract."
      },
      "ControllerStateSource": {
        "enum": [
          "realtime",
          "history"
        ]
      },
      "ControllerStateSourceQueryParameter": {
        "type": "object",
        "properties": {
          "value": {
            "$ref": "#/components/schemas/ControllerStateSource"
          }
        }
      },
      "ControllerTollGatesResponse": {
        "type": "object",
        "properties": {
          "tollGate1": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the first toll gate fed from this cabinet, as the RECO database records\nit. A cabinet detail, not a register."
          },
          "tollGate2": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identifier of the second toll gate fed from this cabinet. Database detail."
          }
        },
        "additionalProperties": false
      },
      "ControllerValveItemResponse": {
        "required": [
          "number",
          "name"
        ],
        "type": "object",
        "properties": {
          "number": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The valve number, matching the number register state reports valve activity under.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "The display name an operator gave this valve, as stored — most names are Hebrew."
          }
        },
        "description": "One named valve on the controller."
      },
      "ControllerValveProgram": {
        "enum": [
          "full",
          "fertilizedUnchained",
          "chainedWithoutFertilizer",
          "plainUnchained"
        ],
        "description": "Which of the four programs a valve is started under.\nThe device names exactly these four and no others, so they are a closed set rather than\ntwo independent flags. Modelling them as \"with fertilizer\" times \"chained\" invents a fifth\ncombination the controller has no address for, and — until the product's own event table\nwas read on 2026-09-01 — mapped two of the real four onto the wrong addresses. A closed\nvocabulary makes the impossible combination unrepresentable instead of refusable."
      },
      "ControllerVersion": {
        "required": [
          "value",
          "kind"
        ],
        "type": "object",
        "properties": {
          "value": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The register's value, as the controller reports it.",
            "format": "int32"
          },
          "kind": {
            "description": "What the value is a version of.",
            "$ref": "#/components/schemas/ControllerVersionKind"
          }
        },
        "description": "A controller's version register, paired with what it is a version of.\nThe third member of the value-shape family, and it exists for the same reason as the other\ntwo. ControllerMeasuredValue pairs a number with a unit that varies by mode;\nControllerCodedState pairs a code with the name a vocabulary gives it; this pairs a\nversion with its subject, which varies by model. The irrigation controller reports a\nhardware revision here and the master and lighting controllers report an unqualified\nversion number, so a single member name could only be right for one of them.",
        "x-controller-values": {
          "value": {
            "kind": "number",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "Owning model version register",
            "events": [ ],
            "evidence": "contract.version"
          },
          "kind": {
            "kind": "enum",
            "origin": "apiPresentation",
            "unit": "none",
            "unitSource": "",
            "encoding": "raw",
            "source": "Owning model's confirmed version-register meaning",
            "events": [ ],
            "evidence": "contract.version"
          }
        }
      },
      "ControllerVersionKind": {
        "enum": [
          "unspecified",
          "hardware"
        ],
        "description": "What a controller's version register is a version <em>of</em>.\nA closed set because it is a RECOM classification of an external fact, not a device code:\nthe models name their version register differently, and this records which naming applies\nrather than letting a consumer guess from the model."
      },
      "ControllerWindowResetResponse": {
        "required": [
          "schemaVersion",
          "windowId",
          "sequence",
          "controllers"
        ],
        "type": "object",
        "properties": {
          "schemaVersion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "windowId": {
            "type": "string",
            "format": "uuid"
          },
          "sequence": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "controllers": {
            "type": "array",
            "items": {
              "required": [
                "id"
              ],
              "type": "object",
              "properties": {
                "id": {
                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                  "type": [
                    "integer",
                    "string"
                  ],
                  "format": "int64"
                },
                "metadata": {
                  "required": [
                    "modelCode",
                    "objectStatus"
                  ],
                  "type": "object",
                  "properties": {
                    "modelCode": {
                      "type": "string"
                    },
                    "objectStatus": {
                      "required": [
                        "code"
                      ],
                      "type": "object",
                      "properties": {
                        "code": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The raw value, as its source reports it.",
                          "format": "int32"
                        },
                        "name": {
                          "type": [
                            "null",
                            "string"
                          ],
                          "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                        }
                      },
                      "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                    }
                  }
                },
                "globalState": {
                  "required": [
                    "code",
                    "name",
                    "isConnected"
                  ],
                  "type": "object",
                  "properties": {
                    "code": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "integer",
                        "string"
                      ],
                      "format": "int32"
                    },
                    "name": {
                      "type": "string"
                    },
                    "isConnected": {
                      "type": "boolean"
                    }
                  }
                },
                "registerState": {
                  "type": "object",
                  "properties": {
                    "batteryVoltage": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "currentFlow": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "totalSlavesFlow": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "alarmActive": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "activeValvesCount": {
                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                      "type": [
                        "null",
                        "integer",
                        "string"
                      ],
                      "format": "int32"
                    },
                    "literPerPulse": {
                      "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                      "type": [
                        "null",
                        "number",
                        "string"
                      ],
                      "format": "double"
                    },
                    "version": {
                      "required": [
                        "value",
                        "kind"
                      ],
                      "type": "object",
                      "properties": {
                        "value": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The register's value, as the controller reports it.",
                          "format": "int32"
                        },
                        "kind": {
                          "enum": [
                            "unspecified",
                            "hardware"
                          ],
                          "description": "            What a controller's version register is a version <em>of</em>.\n            A closed set because it is a RECOM classification of an external fact, not a device code:\nthe models name their version register differently, and this records which naming applies\nrather than letting a consumer guess from the model."
                        }
                      },
                      "description": "            A controller's version register, paired with what it is a version of.\n            The third member of the value-shape family, and it exists for the same reason as the other\ntwo. ControllerMeasuredValue pairs a number with a unit that varies by mode;\nControllerCodedState pairs a code with the name a vocabulary gives it; this pairs a\nversion with its subject, which varies by model. The irrigation controller reports a\nhardware revision here and the master and lighting controllers report an unqualified\nversion number, so a single member name could only be right for one of them."
                    },
                    "isPowerConnected": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "isDoorClosed": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "isSystemDisabled": {
                      "type": [
                        "null",
                        "boolean"
                      ],
                      "description": "The read-only system-disabled status bit (register 0 bit 12, Agam\n`REG:0_BIT13`); `true` is disabled, `false`\nenabled, `null` when the model does not report it. Reported live as\nevents 713 (disabled) and 813 (enabled)."
                    },
                    "isLightOn": {
                      "type": [
                        "null",
                        "boolean"
                      ]
                    },
                    "currentTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "sunriseTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "sunsetTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightOnTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightOffTime": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "lightingControl": {
                      "required": [
                        "mainSwitch",
                        "nonEssentialLighting",
                        "essentialLighting",
                        "generatorBackupLighting",
                        "generator",
                        "schedule"
                      ],
                      "type": "object",
                      "properties": {
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The controller's general alarm bit."
                        },
                        "communicationFault": {
                          "type": "boolean",
                          "description": "The controller detects a communication fault (register 0 bit 15) — the same bit DM\nreports under the same name."
                        },
                        "isControlledByLocalClock": {
                          "type": "boolean",
                          "description": "Lighting is switched by the controller's own clock rather than commanded."
                        },
                        "isWaterLevelLow": {
                          "type": "boolean",
                          "description": "Water level below threshold, reported alongside the generator status."
                        },
                        "mainSwitch": {
                          "type": "object",
                          "properties": {
                            "isLocalControl": {
                              "type": "boolean",
                              "description": "Switched to local control at the cabinet."
                            },
                            "isRemoteControl": {
                              "type": "boolean",
                              "description": "Switched to remote control."
                            },
                            "isOff": {
                              "type": "boolean",
                              "description": "Switched off."
                            }
                          },
                          "description": "Main-switch position of an LT controller, as three independent register bits."
                        },
                        "nonEssentialLighting": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The circuit is energised."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The controller reports a fault on this circuit."
                            },
                            "isDisabled": {
                              "type": "boolean",
                              "description": "The circuit is disabled in configuration, so it will not switch on."
                            }
                          },
                          "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags."
                        },
                        "essentialLighting": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The circuit is energised."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The controller reports a fault on this circuit."
                            },
                            "isDisabled": {
                              "type": "boolean",
                              "description": "The circuit is disabled in configuration, so it will not switch on."
                            }
                          },
                          "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags."
                        },
                        "generatorBackupLighting": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The circuit is energised."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The controller reports a fault on this circuit."
                            },
                            "isDisabled": {
                              "type": "boolean",
                              "description": "The circuit is disabled in configuration, so it will not switch on."
                            }
                          },
                          "description": "One lighting circuit of an LT controller. The three circuits — non-essential,\nessential and generator-backup — carry the same three aspects at different bits of the\nsame registers, so they share one shape rather than nine flat flags."
                        },
                        "generator": {
                          "type": "object",
                          "properties": {
                            "isOn": {
                              "type": "boolean",
                              "description": "The generator is running."
                            },
                            "hasError": {
                              "type": "boolean",
                              "description": "The generator reports a fault."
                            },
                            "isMinimumSwitchOn": {
                              "type": "boolean",
                              "description": "The generator's minimum-level switch is engaged."
                            },
                            "hasBatteryChargerError": {
                              "type": "boolean",
                              "description": "The generator's battery charger reports a fault."
                            },
                            "isFuelLevelLow": {
                              "type": "boolean",
                              "description": "Fuel level is below the configured threshold."
                            }
                          },
                          "description": "Standby-generator status of an LT controller, decoded from the generator register.\nIt backs the essential lighting circuits when mains power fails, so its faults are\noperationally urgent even while the lights are still on."
                        },
                        "isCommunicationPowerDetected": {
                          "type": "boolean",
                          "description": "The communication controller's power detection bit."
                        },
                        "isCommunicationBatteryVoltageOk": {
                          "type": "boolean",
                          "description": "The communication controller reports its battery voltage in range."
                        },
                        "schedule": {
                          "type": "object",
                          "properties": {
                            "onsetMinutes": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "Minutes the light-on moment is shifted relative to the computed sunset.",
                              "format": "int32"
                            },
                            "offsetMinutes": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "Minutes the light-off moment is shifted relative to the computed sunrise.",
                              "format": "int32"
                            },
                            "summerTimeStart": {
                              "required": [
                                "month",
                                "day"
                              ],
                              "type": "object",
                              "properties": {
                                "month": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Calendar month, 1-12 as the device reports it.",
                                  "format": "int32"
                                },
                                "day": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Day of that month, as the device reports it.",
                                  "format": "int32"
                                }
                              },
                              "description": "A calendar day without a year, as the controller configures its summer-time window.\nThe register packs it as day × 100 + month (27 March arrives as 2703); it is split\nhere so no consumer guesses the digit order — live controllers confirm the day-first\npacking, and the reverse reading would produce impossible months."
                            },
                            "summerTimeEnd": {
                              "required": [
                                "month",
                                "day"
                              ],
                              "type": "object",
                              "properties": {
                                "month": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Calendar month, 1-12 as the device reports it.",
                                  "format": "int32"
                                },
                                "day": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "description": "Day of that month, as the device reports it.",
                                  "format": "int32"
                                }
                              },
                              "description": "A calendar day without a year, as the controller configures its summer-time window.\nThe register packs it as day × 100 + month (27 March arrives as 2703); it is split\nhere so no consumer guesses the digit order — live controllers confirm the day-first\npacking, and the reverse reading would produce impossible months."
                            },
                            "doorStatusThresholdTime": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "How long a door state must persist before the controller reports it, in device\ntime units — no available source names the unit, so it is not guessed.",
                              "format": "int32"
                            },
                            "lightStatusThresholdTime": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "null",
                                "integer",
                                "string"
                              ],
                              "description": "How long a light state must persist before the controller reports it, in the same\nunnamed device time units.",
                              "format": "int32"
                            }
                          },
                          "description": "Configured lighting schedule of an LT controller: the offsets and thresholds that\ndecide when the controller switches its circuits, read back exactly as configured."
                        }
                      },
                      "description": "Everything an LT (street-lighting) controller reports beyond the values every model\nshares. Present only for LT controllers on the 1066-register layout; other models and\nthe short layout leave it `null`."
                    },
                    "damControl": {
                      "type": "object",
                      "properties": {
                        "isolationFault": {
                          "type": "boolean",
                          "description": "Isolation fault on the cabinet supply (register 0 bit 2)."
                        },
                        "chargeRelayFault": {
                          "type": "boolean",
                          "description": "Battery charge relay fault (register 0 bit 3)."
                        },
                        "dcConverterFault": {
                          "type": "boolean",
                          "description": "DC converter fault (register 0 bit 4)."
                        },
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The general-alarm status bit (register 0 bit 14), at the same bit as on the\nlighting and irrigation controllers."
                        },
                        "communicationFault": {
                          "type": "boolean",
                          "description": "Communication fault with the cabinet (register 0 bit 15)."
                        },
                        "isCommunicationPowerDetected": {
                          "type": "boolean",
                          "description": "The communication controller reports mains power present (register 36 bit 1)."
                        },
                        "isCommunicationBatteryVoltageOk": {
                          "type": "boolean",
                          "description": "The communication controller reports its battery voltage in range (register 36\nbit 3)."
                        },
                        "clearAlarmsCommand": {
                          "type": "boolean",
                          "description": "State of the clear-alarms command latch; RECOM never sets it."
                        },
                        "configuredDamCount": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Dam count the controller is configured for. `dams` always carries the\nfour the register map covers: trimming to this value would hide a dam reporting\nstate after someone lowered the configured count, which is a fault worth seeing.",
                          "format": "int32"
                        },
                        "communicationFlag": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Vendor communication flag, reported raw.",
                          "format": "int32"
                        },
                        "totalAccumulation": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The controller's accumulating total (register 846), in the device's own\naccumulator units — no source confirms a scale, so the value stays raw rather\nthan guess one.",
                          "format": "int32"
                        },
                        "dams": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "number": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "One-based dam number, as the controller labels it.",
                                "format": "int32"
                              },
                              "isOpen": {
                                "type": "boolean",
                                "description": "The dam is fully open (status register bit 0)."
                              },
                              "isClosed": {
                                "type": "boolean",
                                "description": "The dam is fully closed (status register bit 1)."
                              },
                              "isMoving": {
                                "type": "boolean",
                                "description": "The dam is travelling between its end positions (status register bit 2)."
                              },
                              "isOk": {
                                "type": "boolean",
                                "description": "The dam reports no fault (status register bit 3)."
                              },
                              "hasFeedbackFault": {
                                "type": "boolean",
                                "description": "The dam's position feedback disagrees with its drive (status register bit 15)."
                              },
                              "isControlEnabled": {
                                "type": "boolean",
                                "description": "True when the dam accepts remote open/close commands."
                              },
                              "openCommand": {
                                "type": "boolean",
                                "description": "State of the open command latch. RECOM issues no controller commands; this reports\nwhat the controller currently holds, whoever set it."
                              },
                              "closeCommand": {
                                "type": "boolean",
                                "description": "State of the close command latch; see `openCommand`."
                              }
                            },
                            "description": "One dam of a `DM` controller: where its gate is, whether the feedback agrees, and\nwhether remote control over it is enabled."
                          },
                          "description": "The four dams, in controller order."
                        }
                      },
                      "description": "`DM`-only subsystem detail: cabinet faults, the communication controller, and the\n        four dam gates. Null for every other model and for the short layout."
                    },
                    "irrigation": {
                      "required": [
                        "dayOfWeek",
                        "totalFertilizerLeak"
                      ],
                      "type": "object",
                      "properties": {
                        "clockMinutesFromMidnight": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Controller clock in minutes from midnight. Not the `HHmm` encoding the lighting\nclock uses: the irrigation register genuinely holds minutes, and normalising the two\ninto one field would make a wrong reading indistinguishable from a right one.",
                          "format": "int32"
                        },
                        "dayOfWeek": {
                          "required": [
                            "code"
                          ],
                          "type": "object",
                          "properties": {
                            "code": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "description": "The raw value, as its source reports it.",
                              "format": "int32"
                            },
                            "name": {
                              "type": [
                                "null",
                                "string"
                              ],
                              "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                            }
                          },
                          "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                        },
                        "hasMainValve": {
                          "type": "boolean",
                          "description": "Whether a main valve is fitted: bit 0 of the setup register (17 on the\n548-register layout, 43 on the 1066-register one), which the reference names\n\"Master Valve Exists\". It is also what decides the main valve's port number,\nsince a fitted main valve occupies the last hardware port."
                        },
                        "hardwarePortCount": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "            How many valve ports the controller board has (register 40 on the 548-register\n            layout, 66 on the 1066-register one; reported as analogue event 1713).\n            This is the fact that says which port number the special valves occupy: the\nmain valve is the last port when one is fitted, and the filter valve sits below it,\nbelow the fertilizer valve again when that is fitted too. A command addressed at the\nmain valve without it would either guess a port or refuse to run.",
                          "format": "int32"
                        },
                        "hasFilter": {
                          "type": "boolean",
                          "description": "Whether a filter is fitted (register 42 short, 68 long; analogue event 1715). The\ndevice reports this as a whole register rather than a status bit, so any non-zero\nvalue means fitted."
                        },
                        "filterCount": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How many filters the controller rinses (register 390 short, 761 long; event 2515).\nZero when `hasFilter` is false.",
                          "format": "int32"
                        },
                        "hasFertilizerValve": {
                          "type": "boolean",
                          "description": "Whether a fertilizer valve is fitted: bit 1 of the setup register (17 short, 43\nlong), \"Compost Exists\" in the reference."
                        },
                        "supportsPulses": {
                          "type": "boolean",
                          "description": "Whether pulse irrigation is supported: bit 2 of the setup register (17 short, 43\nlong), \"Allow Pulse Watering\" in the reference."
                        },
                        "isFertilizerByTime": {
                          "type": "boolean",
                          "description": "Whether the controller doses fertilizer by time rather than by quantity (setup\nregister bit 6). It is what decides whether a valve's fertilizer accumulator counts\nhours or litres, so it is published as a fact of its own rather than only as the unit\nbeside that value."
                        },
                        "isFertilizerProportional": {
                          "type": "boolean",
                          "description": "Whether fertilizer is dosed in proportion to the water flowing (setup register bit 7)\nrather than as a fixed amount."
                        },
                        "isRinsingBlockedDuringPipeFill": {
                          "type": "boolean",
                          "description": "Whether the controller refuses to start a filter rinse while pipes are still filling\n(setup register bit 5)."
                        },
                        "isWaterMeterInputOn": {
                          "type": "boolean",
                          "description": "The water meter's input line as the controller last read it: register 2 bit 0,\nreported on by event 733 and off by 833. A live contact, not a presence flag — the\ncontroller re-reports it about once a second while water moves, which the legacy\nUI shows as a pulse indicator on the main valve. Whether a meter is fitted at all\nis `supportsPulses`. A state refresh holds the value at the snapshot; the hub\nwindow carries it as it moves."
                        },
                        "isFertilizerMeterInputOn": {
                          "type": "boolean",
                          "description": "The fertilizer meter's input line (register 2 bit 1; events 734/834). Live, as the water meter's is."
                        },
                        "isPressureMeterInputOn": {
                          "type": "boolean",
                          "description": "The pressure meter's input line (register 2 bit 2; events 735/835)."
                        },
                        "isPressureDifferentialMeterInputOn": {
                          "type": "boolean",
                          "description": "The differential-pressure meter's input line (register 2 bit 3; events 736/836)."
                        },
                        "controllerAddress": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "The controller's own network address (read-only register 39 short, 65 long), the\nsame fact the catalogue already names `controllerAddress` at event 1712.",
                          "format": "int32"
                        },
                        "irrigatingValveNumber": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Number of the valve the controller reports as irrigating now (read-only register 37\nshort, 63 long; event 1710, \"the valve now irrigating\"). Both mapping files name it\n`RO_ActualIrrigationValve`; what the register holds while nothing irrigates is\nstated by no source, so the value is published raw rather than turned into a null.",
                          "format": "int32"
                        },
                        "filterWashBehaviour": {
                          "enum": [
                            "stopIrrigationAndFertilization",
                            "continueIrrigationAndFertilization",
                            "stopFertilizationOnly",
                            "unused"
                          ],
                          "description": "What an I1 controller keeps running while its filter washes, read from bits 0 and 1 of\nthe behaviour register (18 short / 44 long; events 1533/1633 and 1534/1634 respectively)."
                        },
                        "highFlowBehaviour": {
                          "enum": [
                            "closeValveWithAutomaticReset",
                            "closeAndDisableValveWithManualReset",
                            "pauseProgramWithAutomaticReset",
                            "pauseProgramDisableValveWithAutomaticProgramReset"
                          ],
                          "description": "What an I1 controller does when a running program reports a high flow, read from the two\nbits that decide it together: the behaviour register's bit 5 (18 short / 44 long, events\n1538/1638) chooses between closing the offending valve and pausing the whole program, and\nbit 2 of register 393 (764 long, event 2518) chooses between an automatic reset and one a\nperson has to perform."
                        },
                        "continuesIrrigationOnFertilizerFault": {
                          "type": "boolean",
                          "description": "Whether irrigation carries on when the fertilizer system faults (behaviour register\n18 short / 44 long, bit 2; events 1535/1635)."
                        },
                        "opensMainValveBeforeValves": {
                          "type": "boolean",
                          "description": "Whether the main valve opens before the valves it feeds (behaviour register 18\nshort / 44 long, bit 3; events 1536/1636)."
                        },
                        "opensMainValveAfterValves": {
                          "type": "boolean",
                          "description": "Whether the main valve opens after the valves it feeds (behaviour register 18\nshort / 44 long, bit 4; events 1537/1637). The companion of\n`opensMainValveBeforeValves`: the device carries the two orderings as\nseparate bits, so they are published as the two facts it reports."
                        },
                        "allowsValveGrouping": {
                          "type": "boolean",
                          "description": "Whether a valve may open alongside other valves rather than only on its own\n(behaviour register 18 short / 44 long, bit 7; events 1540/1640)."
                        },
                        "isExternalPowerConnected": {
                          "type": "boolean",
                          "description": "Whether external power is connected (register 15 bit 1; events 1150/1250). The\nregister sits in the status zone, so the index is the same on both layouts."
                        },
                        "isCharging": {
                          "type": "boolean",
                          "description": "Whether the controller is charging (register 15 bit 4; events 1153/1253)."
                        },
                        "externalPowerVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "External power supply voltage (register 29 short, 55 long; event 1702), stored in\ntenths of a volt exactly as the battery voltage beside it is.",
                          "format": "double"
                        },
                        "autoNominalFlowChangePercent": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Percentage change applied to the nominal flow in automatic mode (register 80 on\nthe short layout, 451 on the long one).",
                          "format": "int32"
                        },
                        "mainValveDelaySeconds": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Delay before the main valve acts, in seconds (register 377 short, 748 long).",
                          "format": "int32"
                        },
                        "valveOpenVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "null",
                            "number",
                            "string"
                          ],
                          "description": "Solenoid drive voltage in volts — the low byte of the packed valve-drive register\n(79, short layout only), stored in tenths of a volt. Null on the long layout, whose\nequivalent register is unconfirmed. Same fact and name as the IP master's value.",
                          "format": "double"
                        },
                        "valveOpenTimeMs": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "null",
                            "integer",
                            "string"
                          ],
                          "description": "Solenoid drive time in milliseconds — the high byte of the same packed register.",
                          "format": "int32"
                        },
                        "currentFlow": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Current water flow in m³/h — a 32-bit LSW/MSW register pair joined here and scaled\nby the reference's ÷100, so consumers never see the 16-bit seam (registers 30/31 on\nthe short layout, 56/57 on the long one).",
                          "format": "double"
                        },
                        "fertilizerFlow": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Current fertilizer flow in cm³/h (registers 32/33 short, 58/59 long). Scaled by the\nfertilizer meter's own volume per pulse — `cubicCentimetrePerPulse` —\nnot by the water meter's litres multiplier, which is what the water flow beside it\nuses.",
                          "format": "double"
                        },
                        "totalIrrigation": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Accumulated irrigation total in cubic metres (registers 475/476 short, 846/847 long;\nLSW/MSW joined).",
                          "format": "int64"
                        },
                        "totalWaterLeak": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Accumulated water-leak total in cubic metres (registers 477/478 short, 848/849 long).",
                          "format": "int64"
                        },
                        "totalFertilizerLeak": {
                          "required": [
                            "value",
                            "unit"
                          ],
                          "type": "object",
                          "properties": {
                            "value": {
                              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                              "type": [
                                "number",
                                "string"
                              ],
                              "description": "The scaled value, already in the unit named beside it.",
                              "format": "double"
                            },
                            "unit": {
                              "type": "string",
                              "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                            }
                          },
                          "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                        },
                        "totalRinses": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Count of filter rinses performed (register 482 short, 853 long).",
                          "format": "int32"
                        },
                        "remainingMinutesBetweenRinseCycles": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Minutes left until the next rinse cycle (register 277 short, 648 long).",
                          "format": "int32"
                        },
                        "remainingMinutesBetweenRinseValves": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Minutes left before the rinse moves to its next valve (register 278 short, 649\nlong).",
                          "format": "int32"
                        },
                        "remainingRinseTime": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Time left in the running rinse (register 279 short, 650 long). A device time value\nwhose stored resolution no source names, so it is published raw rather than\nguessed.",
                          "format": "int32"
                        },
                        "rinseCyclesWithoutSuccess": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Count of rinse cycles that did not complete (register 376 short, 747 long).",
                          "format": "int32"
                        },
                        "timeBetweenRinsesMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Configured minutes between rinses (register 382 short, 753 long) — counted against\nactual irrigation minutes, not the wall clock.",
                          "format": "int32"
                        },
                        "rinseTimeBetweenValves": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Configured rinse hand-over time from valve to valve, in seconds (register 383 short,\n754 long).",
                          "format": "int32"
                        },
                        "rinseDurationSeconds": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Configured duration of one rinse, in seconds (register 384 short, 755 long).",
                          "format": "int32"
                        },
                        "cubicCentimetrePerPulse": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Cubic centimetres one fertilizer-meter pulse stands for (register 379 short, 750\nlong; event 2504), the fertilizer twin of the controller's water litres-per-pulse.\nIt is also the scale `fertilizerFlow` is computed with, which is why the\nmember is named for the unit it carries rather than for the ratio it expresses.",
                          "format": "int32"
                        },
                        "noIrrigationTime": {
                          "type": "string",
                          "description": "The configured no-irrigation window (register 381 short, 752 long; event 2506, \"a\ntime when watering is not allowed\"), stored as minutes from midnight and published\nas `HH:mm` — the same rendering the lighting clocks get, and the same one the\nevent carries."
                        },
                        "noPulsesAlarmDelayMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How long the controller waits, in minutes, before it raises a no-pulses alarm\n(register 276 short, 647 long; event 2399).",
                          "format": "int32"
                        },
                        "uncontrolledFlowAlarmPulses": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How many pulses the controller counts before it reports an uncontrolled flow\n(register 386 short, 757 long; event 2511).",
                          "format": "int32"
                        },
                        "valvesMeteringWaterOnTimedIrrigation": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Numbers of the valves that meter water while irrigating by time (register 394 short,\n765 long; event 2519, \"measuring water when working by time\"). One bit per valve, as\nthe legacy handler reads it."
                        },
                        "openValves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Numbers of the valves the controller reports as open, whether a program or a person\nopened them (register 1 bits 0-12, valves 1-13, events 717-729). The companion of\n`manuallyOpenedValves`, which narrows that to the hand-opened ones."
                        },
                        "isRinseValveOpen": {
                          "type": "boolean",
                          "description": "Whether the rinse valve is open (register 1 bit 13)."
                        },
                        "manuallyOpenedValves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Numbers of the valves reported as opened manually (register 3 bits 0-12, valves\n1-13 — the register spends its three remaining bits on the rinse, fertilizer and\nmain valves below, so only thirteen numbered valves can carry the flag)."
                        },
                        "valveFaults": {
                          "type": "object",
                          "properties": {
                            "chainingProblem": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a chaining/sequence problem (register 4, events 765-780)."
                            },
                            "highFlowAlarm": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a high-flow alarm (register 5, events 781-796). The controller\nfirmware names it `CRC_REG__ALARM_FLOW_HI_BMP__005` and documents exactly those\nevents, with off twins 881-896."
                            },
                            "lowFlowAlarm": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a low-flow alarm (register 6, events 901-916)."
                            },
                            "fertilizerMissing": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting missing fertilizer material (register 7, events 917-932)."
                            },
                            "stoppedOnTimeLimit": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves the controller stopped because they reached their time limit (register 8,\nevents 933-948)."
                            },
                            "fertilizerLeak": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting a leak in the fertilization system (register 9, events 949-964).\nThe per-valve companion of the controller-wide `hasFertilizerLeak` bit."
                            },
                            "stoppedOnLowPressure": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves the controller stopped for lack of pressure (register 10, events 965-980).\nThe per-valve companion of the controller-wide `isStoppedOnLowPressure` bit."
                            },
                            "frozen": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves held frozen (register 11, events 981-996) — the per-valve companion of the\ncontroller-wide `isFrozen` bit."
                            },
                            "fertilizerDelayed": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves whose fertilization is delayed by the cyclic rule (register 12, events\n1101-1116)."
                            },
                            "irrigatedWithoutFertilizer": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves that irrigated on without their fertilizer (register 13, events 1117-1132).\nDistinct from `fertilizerMissing`: this one says the controller carried on\nregardless."
                            },
                            "noPulses": {
                              "type": "array",
                              "items": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "format": "int32"
                              },
                              "description": "Valves reporting no water-meter pulses (register 14, events 1133-1148)."
                            }
                          },
                          "description": "The irrigation controller's per-valve fault bitmaps: registers 4-14, eleven registers of\nthe status zone that each spend one bit per valve on one kind of fault. A set bit means\nthat valve is currently in that fault; the device raises the on event when it sets and\nthe off twin when it clears."
                        },
                        "isRinseOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the rinse valve was opened manually (register 3 bit 13)."
                        },
                        "isFertilizerValveOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the fertilizer valve was opened manually (register 3 bit 14)."
                        },
                        "isMainValveOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the main valve was opened manually (register 3 bit 15)."
                        },
                        "isRinsing": {
                          "type": "boolean",
                          "description": "Whether the filter is rinsing right now (register 0 bit 0)."
                        },
                        "isWaitingForRinsingMode": {
                          "type": "boolean",
                          "description": "Whether the controller is waiting to enter rinsing mode (register 0 bit 1)."
                        },
                        "isInRinsingCycle": {
                          "type": "boolean",
                          "description": "Whether the controller is currently within a rinsing cycle (register 0 bit 2)."
                        },
                        "isMainValveOpen": {
                          "type": "boolean",
                          "description": "Whether the main valve is open (register 0 bit 3)."
                        },
                        "isInRinsingTransition": {
                          "type": "boolean",
                          "description": "Whether the controller is transitioning between rinsing states (register 0 bit 4)."
                        },
                        "hasWaterLeak": {
                          "type": "boolean",
                          "description": "Whether a systemic water leak is detected (register 0 bit 5)."
                        },
                        "hasFertilizerLeak": {
                          "type": "boolean",
                          "description": "Whether a leak in the fertilization system is detected (register 0 bit 6)."
                        },
                        "isLowInputPressure": {
                          "type": "boolean",
                          "description": "Whether input pressure is missing (register 0 bit 7)."
                        },
                        "isProgramModeWithoutIrrigation": {
                          "type": "boolean",
                          "description": "Whether program mode is active without irrigation (register 0 bit 8). This is the\ndevice's reported fact; it is not inverted into a derived running-state flag."
                        },
                        "isFertilizerValveOpen": {
                          "type": "boolean",
                          "description": "Whether the fertilizer valve is open (register 0 bit 9)."
                        },
                        "isStoppedOnLowPressure": {
                          "type": "boolean",
                          "description": "Whether the system stopped itself on low pressure (register 0 bit 11)."
                        },
                        "isFrozen": {
                          "type": "boolean",
                          "description": "Whether the system is frozen (register 0 bit 10) — the old firmware's\ndisable flag, kept by newer firmware beside the system-disabled bit. The legacy\nconsumer treated frozen-or-disabled as one fact; both are published separately so\nnothing is derived."
                        },
                        "isIrrigatingOrRinsing": {
                          "type": "boolean",
                          "description": "Whether the system is irrigating or rinsing (register 0 bit 13 — the device reports\nthe two as one fact, so they are not split here)."
                        },
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The general-alarm status bit (register 0 bit 14), as on LT and DM."
                        },
                        "isLowVoltage": {
                          "type": "boolean",
                          "description": "Whether the supply voltage is low (register 0 bit 15)."
                        },
                        "valves": {
                          "type": "array",
                          "items": {
                            "required": [
                              "amount",
                              "amountLeft",
                              "amountBeforeFertilizing",
                              "amountAfterFertilizing",
                              "fertilizerAmount",
                              "fertilizerAmountLeft",
                              "totalFertilizer"
                            ],
                            "type": "object",
                            "properties": {
                              "number": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "One-based valve number, as the controller labels it. Not a register of its own: it\nis the slot the valve occupies, and every per-valve register below is read at its\nbase index plus this number minus one.",
                                "format": "int32"
                              },
                              "isActive": {
                                "type": "boolean",
                                "description": "True when the valve is within the controller's active-valve count. Valves past it\nstill hold register values, but the controller does not run them."
                              },
                              "isDisabled": {
                                "type": "boolean",
                                "description": "Whether the valve is disabled in configuration, so the controller will not run\nit. One bit per valve in a single register (392), the valve's own number\nselecting the bit, counting from zero. The long layout stores the same bitmap\nat 763, but carries no valve list to hang it on."
                              },
                              "amount": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "amountLeft": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "amountBeforeFertilizing": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "amountAfterFertilizing": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "cycleDays": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Length of this valve's irrigation cycle in days (register 228 plus the valve slot,\nevents 2351-2366), the interval the weekday list does not express.",
                                "format": "int32"
                              },
                              "cycleDaysLeft": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Days left until this valve's cycle completes (register 146 plus the valve slot,\nevents 1868-1883).",
                                "format": "int32"
                              },
                              "fertilizerAmount": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "fertilizerAmountLeft": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "totalIrrigation": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Everything this valve has irrigated since the accumulator was last reset (registers\n484/485 plus twice the valve slot, joined low word first). Cubic metres: the shipped\nclient's accumulator table heads the column with the unit and applies no scaling to\nthe joined value.",
                                "format": "int64"
                              },
                              "totalFertilizer": {
                                "required": [
                                  "value",
                                  "unit"
                                ],
                                "type": "object",
                                "properties": {
                                  "value": {
                                    "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                    "type": [
                                      "number",
                                      "string"
                                    ],
                                    "description": "The scaled value, already in the unit named beside it.",
                                    "format": "double"
                                  },
                                  "unit": {
                                    "type": "string",
                                    "description": "The fixed unit token this value is in: `minutes`, `seconds` or\n`cubicMetres` for an irrigation amount, `hours` or `litres` for a\nfertilizer accumulator."
                                  }
                                },
                                "description": "A measured register value whose unit is not fixed by the field itself — it depends on a\nsibling mode the device reports, so the value carries its unit rather than make every\nconsumer re-derive it from the mode. The companion of\n`ControllerCodedState`: that pairs a code with its name, this pairs a value with\nits unit."
                              },
                              "pulseCount": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "How many irrigation pulses the valve runs (register 395 plus the valve slot;\ndevice events 2520-2535). Read on the 548-register layout only, like the rest\nof the valve block.",
                                "format": "int32"
                              },
                              "pulseIntervalMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Minutes between those pulses (register 411 plus the valve slot; device events\n2536-2551). Read on the 548-register layout only.",
                                "format": "int32"
                              },
                              "pulseCountLeft": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "How many of those pulses are still to run (register 82 plus the valve slot; device\nevents 1804-1819) — the running counterpart of `pulseCount`. Both mapping\nfiles name it `SP_NumSplashCyclesRemainValve_N`; the legacy handler reads it raw.",
                                "format": "int32"
                              },
                              "pulseIntervalLeft": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Minutes until the next pulse (register 98 plus the valve slot; device events\n1820-1835), the running counterpart of `pulseIntervalMinutes` and stored in the\nsame unit. The mapping files' variable name says days\n(`SP_NumDaysNextSplashValve_N`); the register documentation names minutes, which\nis also what the set point it counts down from is in.",
                                "format": "int32"
                              },
                              "irrigationFactorPercent": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Per-program irrigation-change percentage applied to every amount (register 459 plus\nthe valve slot). Every non-`with` valve of a program must agree on it; a\ndisagreement is reported as a configuration error.",
                                "format": "int32"
                              },
                              "flowMinimum": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "Configured minimum flow in m³/h (the register holds hundredths).",
                                "format": "double"
                              },
                              "flowNominal": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "Configured nominal flow in m³/h (the register holds hundredths).",
                                "format": "double"
                              },
                              "flowMaximum": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "Configured maximum flow in m³/h (the register holds hundredths).",
                                "format": "double"
                              },
                              "lastFlow": {
                                "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                                "type": [
                                  "number",
                                  "string"
                                ],
                                "description": "The last flow the controller calculated for this valve, in m³/h. The register\nholds tenths — unlike the three configured flows above, which hold hundredths —\nbecause that is how both legacy readers of it divide (see the evidence row).",
                                "format": "double"
                              },
                              "lowFlowAlarmDelayMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Delay in minutes before the low-flow alarm raises (register 427 plus the valve\nslot) — a duration, not a flow threshold.",
                                "format": "int32"
                              },
                              "highFlowAlarmDelayMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Delay in minutes before the high-flow alarm raises (register 443 plus the valve\nslot).",
                                "format": "int32"
                              },
                              "fillTimeMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Pipe fill time for this valve, in minutes — how long the line takes to pressurise\nbefore flow measurement is meaningful.",
                                "format": "int32"
                              },
                              "startTimeMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Program start, in minutes from midnight (register 260 plus the valve slot).\nMeaningful only for a first valve.",
                                "format": "int32"
                              },
                              "startTime": {
                                "type": "string",
                                "description": "The same program start as a time of day, `HH:mm` (600 minutes is\n`10:00`). Rendered beside `startTimeMinutes` rather than instead\nof it: the minutes stay the sortable number, and this is what a screen shows.\nRendered once here, as `noIrrigationTime` is, so REST and the hub cannot\nspell one register two ways. Like the minutes, meaningful only for a first valve."
                              },
                              "startWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the valve irrigates on — bits 0-6 of the weekly-schedule register (244\nplus the valve slot; events 2367-2382), as Sunday-first coded pairs (`1` =\n`sunday` … `7` = `saturday`); empty when the valve does not start a\nprogram of its own. The same register's high byte carries\n`fertilizationWeekDays`."
                              },
                              "fertilizationWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the valve fertilizes on — bits 8-14 of the same weekly-schedule\nregister, in the same Sunday-first vocabulary. Bits 7 and 15 are reserved. A valve\nwhose register holds the reserved \"scheduled by another valve\" value reports no\nfertilization days rather than all seven, for the reason its start days are empty."
                              },
                              "startDayRegister": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Raw weekly-schedule register. Kept alongside the two decoded day lists because the\nweekday bits alone cannot express the reserved value that marks a valve as scheduled\nby another one — decoding it would show a valve starting every day when it starts\non none.",
                                "format": "int32"
                              },
                              "startAfterValve": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Valve number this one follows (register 280 plus the valve slot), or 0 when it\nstarts on its own schedule.",
                                "format": "int32"
                              },
                              "startWithValves": {
                                "type": "array",
                                "items": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "format": "int32"
                                },
                                "description": "Valve numbers that open together with this one, from the bitmap at register 296 plus\nthe valve slot — one bit per valve, counting from zero."
                              },
                              "role": {
                                "enum": [
                                  "unassigned",
                                  "first",
                                  "next",
                                  "with"
                                ],
                                "description": "The part a valve plays in the programs decoded from a controller's registers. Derived,\nnot stored: the controller records start days, a predecessor and a \"start with\" mask,\nand the role follows from them."
                              }
                            },
                            "description": "One irrigation valve of an `I1` controller: its configured amount, its flow\nenvelope, and how it is scheduled relative to the other valves."
                          },
                          "description": "The configured valves, in valve order, read from the per-valve register runs of the\n548-register layout. Empty on the 1066-register layout, which stores the same runs\nbut carries no valve list to hang them on."
                        },
                        "programs": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "number": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Sequence number in discovery order (by valve number), one-based.",
                                "format": "int32"
                              },
                              "startTimeMinutes": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "Start, in minutes from midnight.",
                                "format": "int32"
                              },
                              "startTime": {
                                "type": "string",
                                "description": "The same start as a time of day, `HH:mm`, copied from the first valve's\n`startTime` so a program and the valve that starts it never disagree."
                              },
                              "startWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the program starts on, as Sunday-first coded pairs (`1` =\n`sunday` … `7` = `saturday` — the day-of-week vocabulary)."
                              },
                              "fertilizationWeekDays": {
                                "type": "array",
                                "items": {
                                  "required": [
                                    "code"
                                  ],
                                  "type": "object",
                                  "properties": {
                                    "code": {
                                      "pattern": "^-?(?:0|[1-9]\\d*)$",
                                      "type": [
                                        "integer",
                                        "string"
                                      ],
                                      "description": "The raw value, as its source reports it.",
                                      "format": "int32"
                                    },
                                    "name": {
                                      "type": [
                                        "null",
                                        "string"
                                      ],
                                      "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                                    }
                                  },
                                  "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                                },
                                "description": "The weekdays the program fertilizes on, from the high byte of the same first-valve\nregister its start days come from; the same Sunday-first vocabulary."
                              },
                              "factorPercent": {
                                "pattern": "^-?(?:0|[1-9]\\d*)$",
                                "type": [
                                  "integer",
                                  "string"
                                ],
                                "description": "The irrigation-change percentage the program runs at, taken from its valves'\nown factor registers (459 plus the valve slot). Not a register of the program's\nown: a program is reconstructed from its valves, and every non-companion valve\nin one must agree on this number — a disagreement is reported as a\nconfiguration error rather than silently resolved.",
                                "format": "int32"
                              },
                              "valveNumbers": {
                                "type": "array",
                                "items": {
                                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                                  "type": [
                                    "integer",
                                    "string"
                                  ],
                                  "format": "int32"
                                },
                                "description": "Valve numbers in run order: each chained valve followed by the valves that open\nwith it."
                              }
                            },
                            "description": "One irrigation program: a chain of valves that starts together, on the days and at the\ntime its first valve is configured for."
                          },
                          "description": "Programs reconstructed from the valves, earliest start first."
                        },
                        "configurationErrors": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "What did not add up while reconstructing the programs — a valve claimed twice, a\nfactor that disagrees with its program, a start-with pointing at itself. Reported\nrather than thrown: an inconsistent controller still has readable state, and hiding\nthe inconsistency is what makes it hard to find."
                        }
                      },
                      "description": "`I1`-only subsystem detail: the controller clock, whether a main valve is fitted,\n        and — on the short layout, the only one that carries the valve configuration registers —\n        the valves and the programs reconstructed from them."
                    },
                    "irrigationMaster": {
                      "required": [
                        "status",
                        "leakageControlMode"
                      ],
                      "type": "object",
                      "properties": {
                        "hasFlowmeter": {
                          "type": "boolean",
                          "description": "Whether a flowmeter is fitted (setup register 43 bit 0)."
                        },
                        "hasMainValve": {
                          "type": "boolean",
                          "description": "Whether a main valve is fitted (setup register 43 bit 1)."
                        },
                        "calculatesFlow": {
                          "type": "boolean",
                          "description": "Whether the master computes flow rather than only measuring it (setup register\n43 bit 2)."
                        },
                        "hasPump1": {
                          "type": "boolean",
                          "description": "Whether the first pump is fitted (setup register 43 bit 3)."
                        },
                        "hasPump2": {
                          "type": "boolean",
                          "description": "Whether the second pump is fitted (setup register 43 bit 5 — bit 4 belongs to\nneither pump, so the two are not adjacent)."
                        },
                        "isMasterValveOpen": {
                          "type": "boolean",
                          "description": "Whether the master valve is open (register 0 bit 0)."
                        },
                        "isMasterValveOpenedManually": {
                          "type": "boolean",
                          "description": "Whether the master valve was opened manually (register 0 bit 3)."
                        },
                        "hasFlowAlarmByMeasure": {
                          "type": "boolean",
                          "description": "Whether a flow alarm raised from measurement is active (register 0 bit 4)."
                        },
                        "hasFlowAlarmWithoutMeasure": {
                          "type": "boolean",
                          "description": "Whether a flow alarm raised without measurement is active (register 0 bit 5)."
                        },
                        "generalAlarm": {
                          "type": "boolean",
                          "description": "The general-alarm status bit (register 0 bit 7), as on LT, DM and I1."
                        },
                        "batteryStatusCode": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Raw battery-status code (register 55). A plain code, not a\nControllerCodedState: no source confirms a vocabulary for it, and a\npermanently null name would be noise. Labels are client-owned, as with every other\npublished code.",
                          "format": "int32"
                        },
                        "status": {
                          "required": [
                            "code"
                          ],
                          "type": "object",
                          "properties": {
                            "code": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "description": "The raw value, as its source reports it.",
                              "format": "int32"
                            },
                            "name": {
                              "type": [
                                "null",
                                "string"
                              ],
                              "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                            }
                          },
                          "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                        },
                        "leakageControlMode": {
                          "required": [
                            "code"
                          ],
                          "type": "object",
                          "properties": {
                            "code": {
                              "pattern": "^-?(?:0|[1-9]\\d*)$",
                              "type": [
                                "integer",
                                "string"
                              ],
                              "description": "The raw value, as its source reports it.",
                              "format": "int32"
                            },
                            "name": {
                              "type": [
                                "null",
                                "string"
                              ],
                              "description": "The vocabulary's fixed camelCase name for the code, or `null` when\nthe code is outside the confirmed vocabulary."
                            }
                          },
                          "description": "            A value that is a code from a confirmed vocabulary, published as the pair the global\n            state already uses: the raw code stays authoritative, the name is the vocabulary's fixed\n            label, and an unknown code keeps the name null rather than guess.\n            Most are register values, and one is not: the back-office object status is a database\ncolumn. The shape is the same because the reader's problem is the same — a bare number\nthey cannot look up — and one shape learned once beats two that differ only in origin."
                        },
                        "litresPerPulse": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "null",
                            "integer",
                            "string"
                          ],
                          "description": "Litres a flowmeter pulse represents. The register holds a decade code (1, 10, 100,\n1000) which is resolved here, so the value is litres and not a code to look up.\nNull when the register holds none of the four known codes.",
                          "format": "int32"
                        },
                        "leakDetectionMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Leak-detection window in minutes (the reference register is named in minutes).",
                          "format": "int32"
                        },
                        "leakDetectionPercent": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How far past the expected flow counts as a leak, as a percentage (register 454).",
                          "format": "int32"
                        },
                        "uncontrolledFlowDetectionTime": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Uncontrolled-flow detection window, in device time units no source names.",
                          "format": "int32"
                        },
                        "uncontrolledFlowDetectionPulses": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How many flowmeter pulses with no valve open raise uncontrolled flow\n(register 456).",
                          "format": "int32"
                        },
                        "closeValveDelaySeconds": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Seconds the master waits before rejecting a close (named in seconds by the reference).",
                          "format": "int32"
                        },
                        "valveOpenVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Solenoid open drive voltage in volts (register 458, stored in tenths of a volt).\nSame fact and name as the irrigation controller's value.",
                          "format": "double"
                        },
                        "valveOpenTimeMs": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Solenoid open drive time in milliseconds (named in ms by the reference).",
                          "format": "int32"
                        },
                        "valveCloseVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Solenoid close drive voltage in volts (register 460, tenths of a volt).",
                          "format": "double"
                        },
                        "valveCloseTimeMs": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Solenoid close drive time in milliseconds (named in ms by the reference).",
                          "format": "int32"
                        },
                        "manualOpenMinutes": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "How long a manual pump or valve activation runs, in minutes (register 462).",
                          "format": "int32"
                        },
                        "mainValveSlaves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Slave numbers (1-32) that irrigate through this master's main valve."
                        },
                        "pump1Slaves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Slave numbers (1-32) that draw through the first pump — two registers from 604,\nlow word first. The device stores these inverted, so a clear bit means the\nslave uses the pump; the inversion is undone in the register map so no consumer\nrepeats it."
                        },
                        "pump2Slaves": {
                          "type": "array",
                          "items": {
                            "pattern": "^-?(?:0|[1-9]\\d*)$",
                            "type": [
                              "integer",
                              "string"
                            ],
                            "format": "int32"
                          },
                          "description": "Slave numbers (1-32) that draw through the second pump — two registers from 606,\ninverted the same way."
                        }
                      },
                      "description": "`IP`-only subsystem detail: which hardware the master has, how it handles leaks,\n        how its valves are driven, and which slaves share its main valve and pumps. Null for\n        every other model and for the short layout, which reports none of it."
                    },
                    "weatherStation": {
                      "type": "object",
                      "properties": {
                        "barometer": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Barometric pressure in mmHg (register 57, thousandths of inHg × 25.4 ÷ 1000).",
                          "format": "double"
                        },
                        "outsideTemperature": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Outside temperature in °C (register 60, tenths of °F).",
                          "format": "double"
                        },
                        "windSpeed": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Wind speed in km/h (register 61, mph × 1.609344).",
                          "format": "double"
                        },
                        "windSpeed10MinuteAverage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Ten-minute average wind speed in km/h (register 62, tenths of mph).",
                          "format": "double"
                        },
                        "outsideHumidity": {
                          "pattern": "^-?(?:0|[1-9]\\d*)$",
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Outside relative humidity in percent (register 79, raw).",
                          "format": "int32"
                        },
                        "rainRate": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Rain rate in mm/h (register 87, 0.254 mm collector clicks).",
                          "format": "double"
                        },
                        "dayRain": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Rain accumulated today in mm (register 92, 0.254 mm collector clicks).",
                          "format": "double"
                        },
                        "dayEvaporation": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Evapotranspiration accumulated today in mm (register 95, thousandths of an inch).",
                          "format": "double"
                        },
                        "consoleBatteryVoltage": {
                          "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
                          "type": [
                            "number",
                            "string"
                          ],
                          "description": "Console battery voltage (register 122, Davis encoding raw × 300 ÷ 512 ÷ 100).\nReplaces the register-62 value this model briefly published as a battery: two\nreference artifacts and live snapshots agree register 62 is the ten-minute average\nwind speed, now published under that fact's own name above.",
                          "format": "double"
                        }
                      },
                      "description": "`WE`-only subsystem detail: the Davis weather-station LOOP measurements the long\n        layout mirrors into registers 54-126. Null for every other model and for the short\n        layout, whose weather registers carry placeholders only."
                    },
                    "syncedAtUtc": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CreateSessionRequest": {
        "required": [
          "username",
          "password",
          "installationId",
          "platform",
          "appVersion"
        ],
        "type": "object",
        "properties": {
          "username": {
            "type": "string",
            "description": "RECO account name, verified by the external authentication service.",
            "example": "sample-user"
          },
          "password": {
            "type": "string",
            "description": "RECO account password. Sent only over TLS; never stored or logged.",
            "example": "entered-on-device"
          },
          "installationId": {
            "type": "string",
            "description": "Stable per-install identifier (UUID) generated by the mobile app at first launch.\nIt is sealed into the continuation token: refreshing a session only works from the\nsame installation, so a copied token is useless elsewhere.",
            "format": "uuid",
            "example": "0190f1d2-3c4b-7a89-b012-3456789abcde"
          },
          "platform": {
            "description": "Client OS family. Recorded for support diagnostics.",
            "examples": [
              "ios"
            ],
            "$ref": "#/components/schemas/MobilePlatform"
          },
          "appVersion": {
            "type": "string",
            "description": "Mobile app version, e.g. \"1.4.0\". Recorded for support diagnostics.",
            "example": "1.0.0"
          }
        },
        "description": "Login request. Non-positional class: the password must never reach ToString()/logs."
      },
      "CreateSessionResponse": {
        "required": [
          "accessToken",
          "accessTokenExpiresAtUtc",
          "continuationToken",
          "continuationTokenExpiresAtUtc",
          "user"
        ],
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "accessTokenExpiresAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "continuationToken": {
            "type": "string"
          },
          "continuationTokenExpiresAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "user": {
            "description": "Verified identity summary shared by the authentication use cases that return tokens.\nFeature-level because CreateSession and RefreshSession publish the identical shape.",
            "$ref": "#/components/schemas/AuthenticatedUserResponse"
          }
        },
        "description": "Issued tokens and identity. Non-positional class: token values stay out of ToString()."
      },
      "EventCatalogEventItemResponse": {
        "required": [
          "eventNumber",
          "registerNumber",
          "bitIndex",
          "registerKind",
          "isDigital",
          "cadence"
        ],
        "type": "object",
        "properties": {
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Number reported when the value turns on, or when an analogue value changes.",
            "format": "int32",
            "example": 701
          },
          "offEventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Number reported when the value turns off. Omitted for analogue parameters, which\nhave no off twin. Subscribing to a boolean parameter means naming both numbers.",
            "format": "int32",
            "example": 801
          },
          "parameterName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Confirmed parameter name, as it arrives on the hub. Null when RECOM cannot name this\nevent for this model — the event still arrives, as `Unclassified`, with its\nnumber and address intact, and `displayLabels` may still describe it.",
            "example": "powerStatus"
          },
          "valueKind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "How the raw integer should be read. Null wherever `parameterName` is.",
                "$ref": "#/components/schemas/ControllerEventValueKind"
              }
            ]
          },
          "registerNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Zero-based register the event addresses.",
            "format": "int32",
            "example": 0
          },
          "bitIndex": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Zero-based bit within that register; 0 for analogue parameters. Agam's register\ndocumentation numbers bits from one, so bit index 15 is its bit 16.",
            "format": "int32",
            "example": 0
          },
          "registerKind": {
            "description": "Which of the five register zones the address falls in.",
            "$ref": "#/components/schemas/ControllerRegisterKind"
          },
          "isDigital": {
            "type": "boolean",
            "description": "True when the event reports a single bit, false when it reports the whole register.\nDigital events are the ones with an off twin."
          },
          "cadence": {
            "description": "`onChange` for an event that reports a change; `continuous` where it mirrors\na physical input line the controller re-reports about once a second — a meter's pulse\ncontact. A continuous event is a stream to watch on the hub, and the push catalogue\nopt-in never admits it.",
            "examples": [
              "onChange"
            ],
            "$ref": "#/components/schemas/ControllerEventCadence"
          },
          "displayLabels": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The Agam reference's display text, omitted where it labels nothing. Unreviewed\nupstream UI strings — see EventCatalogLabelResponse before rendering\nthem as anything but a hint.",
                "$ref": "#/components/schemas/EventCatalogLabelResponse"
              }
            ]
          }
        },
        "description": "One device event. `eventNumber` and `modelCode` are exactly the pair a\n`SpecificEvents` hub subscription names."
      },
      "EventCatalogLabelResponse": {
        "type": "object",
        "properties": {
          "he": {
            "type": [
              "null",
              "string"
            ],
            "description": "Hebrew label, omitted where the reference has none. Present for LT, DM, I1 and IP.",
            "example": "מפסק ראשי במצב מקומי"
          },
          "en": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latin label, omitted where the reference has none. Present for I1, IP and WE, and\nmachine-translated from the Hebrew for the two irrigation models.",
            "example": "Barometer"
          }
        },
        "description": "The Agam reference's own display text for an event, by language.\nNot a parameter name. These are another product's UI strings, carried\nverbatim so a client can show a human something for an event RECOM cannot name. The\nLatin text is a machine translation of the Hebrew and reads like one; treat it as a hint\nto an operator, never as an identifier, a key, or a substitute for\nparameterName."
      },
      "EventCatalogModelItemResponse": {
        "required": [
          "modelCode",
          "events"
        ],
        "type": "object",
        "properties": {
          "modelCode": {
            "type": "string",
            "description": "RECO model code.",
            "example": "LT"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventCatalogEventItemResponse"
            }
          }
        },
        "description": "Every catalogued parameter of one controller model, by event number."
      },
      "GetControllerCommandCapabilitiesResponse": {
        "required": [
          "capabilities"
        ],
        "type": "object",
        "properties": {
          "capabilities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerCommandCapability"
            },
            "description": "The capabilities held, in a fixed order: `operate` (stop and hand-operate valves, the\nmaster and filter valves, the master controller's mode, clear errors),\n`startProgrammedIrrigation` (start a valve's program or a whole program),\n`resetAccumulators` (zero the totals) and `administer` (in or out of service,\nrestarts, overwrite a running countdown). Empty when the user may command nothing here."
          }
        },
        "additionalProperties": false,
        "description": "What this user may tell controllers to do in the project. Advisory: a client uses it to\nshow or hide controls, and every command is re-authorized when it is sent."
      },
      "GetControllerDetailsResponse": {
        "required": [
          "id",
          "deviceState"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "hwid": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "hwidEx": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "deviceType": {
            "type": [
              "null",
              "string"
            ]
          },
          "deviceType2": {
            "type": [
              "null",
              "string"
            ]
          },
          "objectStatus": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The back-office status of the controller's record, with its vocabulary name. Not\nthe live device status — that is ControllerGlobalStateResponse? GetControllerDetailsResponse.GlobalState.",
                "$ref": "#/components/schemas/ControllerCodedState"
              }
            ]
          },
          "globalState": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerGlobalStateResponse"
              }
            ]
          },
          "deviceState": {
            "$ref": "#/components/schemas/ControllerDeviceStateResponse"
          },
          "notes": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsNotesResponse"
              }
            ]
          },
          "customer": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsCustomerResponse"
              }
            ]
          },
          "hardware": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsHardwareResponse"
              }
            ]
          },
          "communication": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsCommunicationResponse"
              }
            ]
          },
          "installation": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsInstallationResponse"
              }
            ]
          },
          "location": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsLocationResponse"
              }
            ]
          },
          "lifecycle": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsLifecycleResponse"
              }
            ]
          },
          "area": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsAreaResponse"
              }
            ]
          },
          "contractor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsContractorResponse"
              }
            ]
          },
          "personnel": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ControllerDetailsPersonnelResponse"
              }
            ]
          },
          "lighting": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The lighting cabinet's installation context. Present only for a lighting\ncontroller, and only when the back office records any of it.",
                "$ref": "#/components/schemas/ControllerDetailsLightingResponse"
              }
            ]
          }
        },
        "additionalProperties": false,
        "description": "The full detail record of one controller. Identity, object status, available global state,\nand the exact device state are at the top level; the remaining values use eleven\noptional groups:\nControllerDetailsNotesResponse? GetControllerDetailsResponse.Notes, ControllerDetailsCustomerResponse? GetControllerDetailsResponse.Customer, ControllerDetailsHardwareResponse? GetControllerDetailsResponse.Hardware,\nControllerDetailsCommunicationResponse? GetControllerDetailsResponse.Communication, ControllerDetailsInstallationResponse? GetControllerDetailsResponse.Installation, ControllerDetailsLocationResponse? GetControllerDetailsResponse.Location,\nControllerDetailsLifecycleResponse? GetControllerDetailsResponse.Lifecycle, ControllerDetailsAreaResponse? GetControllerDetailsResponse.Area, ControllerDetailsContractorResponse? GetControllerDetailsResponse.Contractor, and\nControllerDetailsPersonnelResponse? GetControllerDetailsResponse.Personnel, and ControllerDetailsLightingResponse? GetControllerDetailsResponse.Lighting. Null members and wholly empty\ngroups are omitted. Codes are raw\nvalues; label decoding is client-owned."
      },
      "GetControllerRegistersResponse": {
        "required": [
          "id",
          "source"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "source": {
            "type": "string",
            "description": "Where the values came from: `realtime` or `history`."
          },
          "layout": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The register file's length — 548 or 1066 for the known firmware layouts. Absent\ntogether with the register list when the store holds no parseable payload.",
            "format": "int32"
          },
          "syncedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "registers": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ControllerRegisterItemResponse"
            },
            "description": "Every register in file order; absent when the store holds no payload."
          }
        },
        "description": "One controller's raw register file, joined server-side with the event directory so a\nclient renders and never decodes. Values are the store's own numbers — no scaling, no\ninterpretation; the decoded, typed view of the same registers is the model-details\ncontract."
      },
      "GetControllerStatesRequest": {
        "type": "object",
        "properties": {
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Which project the refresh reads. Omit it — the default — to read the project the\naccess token was issued for, which performs no extra query. A project the caller does\nnot hold is refused; the identity used inside a project is resolved on the server and\ncan never be supplied by a request.",
            "format": "int64",
            "example": 88
          },
          "scope": {
            "description": "Which controllers to refresh: `explicit` (default — the ids below) or\n`authorized` (every controller the token grants, with no id list). Omitting it\nkeeps the enumerated-ids contract, so existing clients are unaffected.",
            "examples": [
              "explicit"
            ],
            "$ref": "#/components/schemas/ControllerStateScope"
          },
          "controllerIds": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            },
            "description": "Controller ids to refresh; 1–500 per call, duplicates ignored. Required for\n`explicit` scope and must be empty for `authorized`.",
            "example": [
              17537,
              27816
            ]
          }
        },
        "description": "State refresh for specific controllers.\nIds outside the caller's authorized set are silently omitted from the response —\nthey can never probe the authorized set. User and customer scope always come from\nthe bearer token, never from the request."
      },
      "GetControllerStatesResponse": {
        "required": [
          "items"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerStateItemResponse"
            }
          }
        },
        "additionalProperties": false,
        "description": "States for the requested authorized controllers; unauthorized or unknown ids are absent."
      },
      "GetControllerValvesResponse": {
        "required": [
          "valves"
        ],
        "type": "object",
        "properties": {
          "valves": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerValveItemResponse"
            }
          }
        },
        "description": "The named irrigation valves of one controller, ordered by valve number."
      },
      "GetCurrentUserResponse": {
        "required": [
          "userId",
          "username",
          "customerId",
          "sessionId",
          "apiVersion",
          "buildVersion",
          "environmentName",
          "serverName",
          "databaseServer",
          "databaseCatalog"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "RECO user id carried by the validated access token.",
            "format": "int64"
          },
          "username": {
            "type": "string",
            "description": "RECO account name carried by the token."
          },
          "customerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "RECO customer id carried by the token.",
            "format": "int64"
          },
          "sessionId": {
            "type": "string",
            "description": "Identifier of the session the token belongs to."
          },
          "apiVersion": {
            "type": "string",
            "description": "Informational assembly version of the running API, for example `1.4.0+3f2a1c9`."
          },
          "buildVersion": {
            "type": "string",
            "description": "Assembly version of the running API, for example `1.4.0.0`."
          },
          "environmentName": {
            "type": "string",
            "description": "Host environment of the answering process, for example `Development`."
          },
          "serverName": {
            "type": "string",
            "description": "Machine name of the answering process."
          },
          "databaseServer": {
            "type": [
              "null",
              "string"
            ],
            "description": "RECO database server the API reads, without credentials."
          },
          "databaseCatalog": {
            "type": [
              "null",
              "string"
            ],
            "description": "RECO database catalog the API reads."
          }
        },
        "description": "Token-derived identity echo plus the deployment description of the answering process,\nfor diagnostics and app display. Support asks \"which build, which server, which\ndatabase\" first, so those answers travel with the identity instead of only reaching the\nlogs. No credential or connection-string secret is ever included."
      },
      "GetEventCatalogResponse": {
        "required": [
          "models"
        ],
        "type": "object",
        "properties": {
          "models": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventCatalogModelItemResponse"
            }
          }
        },
        "description": "The device event catalogue: which controller models RECOM can name parameters for, and\nevery parameter of each."
      },
      "GetLogFileResponse": {
        "required": [
          "fileName",
          "sizeBytes",
          "lastWrittenAtUtc",
          "hasMore",
          "lines"
        ],
        "type": "object",
        "properties": {
          "fileName": {
            "type": "string",
            "description": "File name inside the log directory."
          },
          "sizeBytes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Full file size in bytes (the tail may cover less).",
            "format": "int64"
          },
          "lastWrittenAtUtc": {
            "type": "string",
            "description": "Instant of the last write, UTC.",
            "format": "date-time"
          },
          "hasMore": {
            "type": "boolean",
            "description": "True when the file holds earlier lines beyond the returned tail."
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Newest lines in file order; each line is one compact-JSON log event."
          }
        },
        "description": "The bounded tail of one rolling log file."
      },
      "GetPushSubscriptionOptionsResponse": {
        "required": [
          "authorizedControllerIds",
          "allowedEvents",
          "defaultEvents",
          "clientApplications",
          "subscriptionModes",
          "controllerScopes",
          "maximumControllersPerSubscription",
          "maximumEventsPerSubscription",
          "allowTestSend"
        ],
        "type": "object",
        "properties": {
          "authorizedControllerIds": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          },
          "allowedEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PushSubscriptionEventItemResponse"
            }
          },
          "defaultEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PushSubscriptionEventItemResponse"
            }
          },
          "clientApplications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PushSubscriptionClientApplicationItemResponse"
            }
          },
          "subscriptionModes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "controllerScopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "maximumControllersPerSubscription": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "maximumEventsPerSubscription": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "allowTestSend": {
            "type": "boolean"
          }
        },
        "description": "Allowed notification subscription choices for the authenticated caller."
      },
      "GetServiceCallVocabularyResponse": {
        "required": [
          "statuses",
          "faultEquipment",
          "actions",
          "replacedEquipment",
          "technicians"
        ],
        "type": "object",
        "properties": {
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
            },
            "description": "Where a call can stand. Codes at or above 80 are closed states."
          },
          "faultEquipment": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
            },
            "description": "What can be reported faulty, and the values a write accepts."
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
            },
            "description": "What a technician can record having done. Read-only on this API."
          },
          "replacedEquipment": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
            },
            "description": "What a technician can record replacing. Read-only on this API."
          },
          "technicians": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCallTechnicianItemResponse"
            },
            "description": "The users a call may be assigned to."
          }
        },
        "description": "The accepted values for a service call, and the technicians one may be assigned to."
      },
      "ListControllersResponse": {
        "required": [
          "items"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerItemResponse"
            }
          }
        },
        "additionalProperties": false,
        "description": "The caller's complete authorized controller list. No paging: the pilot\ndata set is bounded and the mobile client filters locally."
      },
      "ListedPushSubscriptionEventItemResponse": {
        "required": [
          "source",
          "modelCode",
          "eventNumber"
        ],
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        },
        "description": "A configured controller-event key selected for a notification subscription."
      },
      "ListLogFilesItemResponse": {
        "required": [
          "fileName",
          "sizeBytes",
          "lastWrittenAtUtc"
        ],
        "type": "object",
        "properties": {
          "fileName": {
            "type": "string",
            "description": "File name inside the log directory; pass it to `GET /api/v1/logs/{fileName}`.",
            "example": "recom-backend-20260718.ndjson"
          },
          "sizeBytes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Current size in bytes.",
            "format": "int64"
          },
          "lastWrittenAtUtc": {
            "type": "string",
            "description": "Instant of the last write, UTC.",
            "format": "date-time"
          }
        },
        "description": "One rolling log file currently on disk."
      },
      "ListLogFilesResponse": {
        "required": [
          "files"
        ],
        "type": "object",
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListLogFilesItemResponse"
            }
          }
        },
        "description": "The log files currently on disk, newest first."
      },
      "ListPushSubscriptionsResponse": {
        "required": [
          "subscriptions"
        ],
        "type": "object",
        "properties": {
          "subscriptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PushSubscriptionItemResponse"
            }
          }
        },
        "description": "The caller's notification subscriptions without installation identifiers."
      },
      "ListServiceCallsResponse": {
        "required": [
          "serviceCalls",
          "truncated"
        ],
        "type": "object",
        "properties": {
          "serviceCalls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceCallResponse"
            },
            "description": "The calls, ordered by opening date and then call number, both descending."
          },
          "truncated": {
            "type": "boolean",
            "description": "True when more calls matched than the limit allowed. Narrow the filter or raise the limit;\nthere is no continuation token."
          }
        },
        "description": "The service calls matching the request, newest first."
      },
      "ListUserProjectsItemResponse": {
        "required": [
          "customerId",
          "customerName",
          "isCurrent",
          "isFavorite",
          "loginCount",
          "lastLoginOn"
        ],
        "type": "object",
        "properties": {
          "customerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Identifier of the project.",
            "format": "int64"
          },
          "customerName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Display name of the project, omitted when the record has none."
          },
          "isCurrent": {
            "type": "boolean",
            "description": "True for the project the current access token is scoped to."
          },
          "isFavorite": {
            "type": "boolean",
            "description": "True when the user has flagged this project as a favorite."
          },
          "loginCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many times the user has opened this project.",
            "format": "int32"
          },
          "lastLoginOn": {
            "type": [
              "null",
              "string"
            ],
            "description": "Date of the user's most recent login to this project, omitted when they have never opened it.",
            "format": "date"
          }
        },
        "description": "One project the authenticated user is authorized to work in."
      },
      "ListUserProjectsResponse": {
        "required": [
          "items"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListUserProjectsItemResponse"
            },
            "description": "Every authorized project. Empty when the user holds none."
          }
        },
        "description": "The caller's complete authorized project list, ordered by project name. No paging: a user\nholds few enough projects for one response, and the client renders them as a single picker."
      },
      "MobilePlatform": {
        "enum": [
          "ios",
          "android"
        ],
        "description": "Client OS family of the RECOM mobile app, serialized as a lowercase string\n(\"ios\"/\"android\"). An unrecognized value fails JSON binding as request.malformed,\nso the contract is closed by construction; extend the enum when a new platform ships."
      },
      "OpenServiceCallRequest": {
        "required": [
          "controllerId",
          "faultEquipmentCode",
          "faultDescription"
        ],
        "type": "object",
        "properties": {
          "controllerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The controller the fault is on — an id from GET /api/v1/controllers. It must be one this\nuser is authorized to work in; anything else is refused, whether or not it exists.",
            "format": "int64"
          },
          "faultEquipmentCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "What is faulty, from the fault equipment list in GET /api/v1/service-calls/vocabulary.",
            "format": "int32"
          },
          "faultDescription": {
            "type": "string",
            "description": "What is wrong, in the reporter's own words. At most 250 characters — the store keeps no\nmore, and a longer value is refused rather than silently cut."
          },
          "priority": {
            "description": "How urgently the call should be handled. Defaults to urgent.",
            "$ref": "#/components/schemas/ServiceCallPriority"
          },
          "statusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The status to open the call in, from the status list in the vocabulary. Defaults to the\nnew-fault status.",
            "format": "int32",
            "default": 0
          },
          "assignedTechnicianId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The technician to hand the call to, from the technicians in the vocabulary. Omit to leave\nthe call unassigned.",
            "format": "int64"
          },
          "notesForTechnician": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instructions for whoever handles the call. At most 100 characters, for the same reason as\nthe description."
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Open the call in another project this user is authorized to work in — a customerId from\nGET /api/v1/auth/projects. Omit it to use the project the access token was issued for.",
            "format": "int64"
          }
        },
        "description": "A fault to report against one controller."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "PushControllerScope": {
        "enum": [
          "explicit",
          "authorized"
        ]
      },
      "PushPlatform": {
        "enum": [
          "Web",
          "Android",
          "Ios"
        ]
      },
      "PushSubscriptionClientApplicationItemResponse": {
        "required": [
          "platform",
          "firebaseAppId",
          "clickTarget"
        ],
        "type": "object",
        "properties": {
          "platform": {
            "type": "string"
          },
          "firebaseAppId": {
            "type": "string"
          },
          "clickTarget": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "A Firebase application that the current client may register for notifications."
      },
      "PushSubscriptionEventItemResponse": {
        "required": [
          "source",
          "modelCode",
          "eventNumber",
          "offEventNumber",
          "eventName",
          "globalStates"
        ],
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Event source the key subscribes to (`DeviceChange` or `Elog`)."
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ],
            "description": "Controller model the key is scoped to, or `null` for any model."
          },
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Event number the key subscribes to — for a digital device event, its on number.",
            "format": "int32"
          },
          "offEventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Off twin of a digital device event, or `null`. Subscribing to\nEventNumber also delivers this number: one parameter, two numbers.",
            "format": "int32"
          },
          "eventName": {
            "type": [
              "null",
              "string"
            ],
            "description": "Confirmed name of the event — `Global state` or the catalogued parameter name — or\n`null` when no confirmed name exists."
          },
          "globalStates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PushSubscriptionGlobalStateItemResponse"
            },
            "description": "For the global-state event, the state codes the server-side policy delivers, each with\nits display name and connectivity meaning. Empty for every other event."
          }
        },
        "description": "A server-approved controller-event key available to notification subscriptions."
      },
      "PushSubscriptionGlobalStateItemResponse": {
        "required": [
          "code",
          "name",
          "isConnected"
        ],
        "type": "object",
        "properties": {
          "code": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Numeric state code as carried by the global-state event.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "Display name of the state."
          },
          "isConnected": {
            "type": "boolean",
            "description": "Whether the state reports the controller as connected."
          }
        },
        "description": "One controller global state a push subscription can be notified about."
      },
      "PushSubscriptionItemResponse": {
        "required": [
          "id",
          "platform",
          "firebaseAppId",
          "mode",
          "isEnabled",
          "controllerIds",
          "eventKeys",
          "createdAtUtc",
          "updatedAtUtc",
          "deactivatedAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "platform": {
            "type": "string"
          },
          "firebaseAppId": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "isEnabled": {
            "type": "boolean"
          },
          "controllerIds": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          },
          "eventKeys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListedPushSubscriptionEventItemResponse"
            }
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "deactivatedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "description": "A caller-owned notification subscription and its server-approved filters."
      },
      "PushSubscriptionMode": {
        "enum": [
          "Default",
          "SpecificEvents"
        ]
      },
      "RefreshSessionRequest": {
        "required": [
          "continuationToken",
          "installationId"
        ],
        "type": "object",
        "properties": {
          "continuationToken": {
            "type": "string"
          },
          "installationId": {
            "type": "string",
            "description": "Must match the installation the continuation token was issued to.",
            "format": "uuid"
          }
        },
        "description": "Continuation request. Non-positional class: it carries the opaque token."
      },
      "RefreshSessionResponse": {
        "required": [
          "accessToken",
          "accessTokenExpiresAtUtc",
          "continuationToken",
          "continuationTokenExpiresAtUtc",
          "user"
        ],
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "accessTokenExpiresAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "continuationToken": {
            "type": "string"
          },
          "continuationTokenExpiresAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "user": {
            "description": "Verified identity summary shared by the authentication use cases that return tokens.\nFeature-level because CreateSession and RefreshSession publish the identical shape.",
            "$ref": "#/components/schemas/AuthenticatedUserResponse"
          }
        },
        "description": "Replacement tokens. The continuation expiry never moves past the original absolute\nexpiry established at credential login. Non-positional class: it carries token values."
      },
      "SendPushTestNotificationResponse": {
        "required": [
          "deliveryId"
        ],
        "type": "object",
        "properties": {
          "deliveryId": {
            "type": "string",
            "format": "uuid"
          }
        },
        "description": "Identifier of an accepted diagnostic-notification delivery attempt."
      },
      "ServiceCallCodedValueResponse": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "One value from a stored service-call vocabulary."
      },
      "ServiceCallPriority": {
        "enum": [
          "unknown",
          "normal",
          "urgent",
          "critical"
        ],
        "description": "How urgently a call should be handled. A closed set: the stored column holds 0, 1 or 2\nacross every row of the existing table, and the legacy client names exactly those three.\n`unknown` is published for a stored value outside them and is never accepted on a\nrequest — send normal, urgent or critical."
      },
      "ServiceCallResponse": {
        "required": [
          "id",
          "priority"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The call number, stable for the life of the call.",
            "format": "int64"
          },
          "openedOn": {
            "type": [
              "null",
              "string"
            ],
            "description": "The day the call was opened. A date rather than a timestamp because the record keeps no\ntime of day.",
            "format": "date"
          },
          "closedOn": {
            "type": [
              "null",
              "string"
            ],
            "description": "The day the call was closed, when it has been. A call moved to a finished status through\nthis API keeps an empty closing date — see the API contract.",
            "format": "date"
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Where the call stands. Codes and names come from the stored status vocabulary.",
                "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
              }
            ]
          },
          "priority": {
            "description": "How urgently the call should be handled.",
            "$ref": "#/components/schemas/ServiceCallPriority"
          },
          "controllerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The controller the call is about, as returned by GET /api/v1/controllers.",
            "format": "int64"
          },
          "controllerName": {
            "type": [
              "null",
              "string"
            ]
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The project the controller belongs to.",
            "format": "int64"
          },
          "projectName": {
            "type": [
              "null",
              "string"
            ]
          },
          "openedByUserId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int64"
          },
          "openedByUserName": {
            "type": [
              "null",
              "string"
            ]
          },
          "faultEquipment": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The equipment reported faulty.",
                "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
              }
            ]
          },
          "faultDescription": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the reporter described."
          },
          "notesForTechnician": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instructions left for whoever handles the call."
          },
          "assignedTechnicianId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The technician holding the call, absent while nobody does.",
            "format": "int64"
          },
          "assignedTechnicianName": {
            "type": [
              "null",
              "string"
            ]
          },
          "treatment": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "What a technician recorded doing, present only once something was recorded. Read-only:\nno request this API accepts can set any of it.",
                "$ref": "#/components/schemas/ServiceCallTreatmentResponse"
              }
            ]
          }
        },
        "description": "One service call: a fault reported against a controller, how it was triaged, and — once a\ntechnician has handled it — what was done."
      },
      "ServiceCallTechnicianItemResponse": {
        "required": [
          "id",
          "name"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The value to send as assignedTechnicianId.",
            "format": "int64"
          },
          "name": {
            "type": "string"
          }
        },
        "description": "One technician a call may be assigned to."
      },
      "ServiceCallTreatmentResponse": {
        "type": "object",
        "properties": {
          "takenAction": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The action taken, from the stored action vocabulary.",
                "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
              }
            ]
          },
          "actionDescription": {
            "type": [
              "null",
              "string"
            ],
            "description": "The technician's own description of the work."
          },
          "replacedEquipment1": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The first piece of equipment replaced, if any.",
                "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
              }
            ]
          },
          "replacedEquipment2": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The second piece of equipment replaced, if any.",
                "$ref": "#/components/schemas/ServiceCallCodedValueResponse"
              }
            ]
          }
        },
        "description": "What a technician recorded against a call. Every member is read-only: this API can move a\ncall's status but cannot record treatment, so these values come from whatever system did."
      },
      "SetProjectFavoriteRequest": {
        "required": [
          "isFavorite"
        ],
        "type": "object",
        "properties": {
          "isFavorite": {
            "type": "boolean",
            "description": "True to flag the project as a favorite, false to clear the flag."
          }
        },
        "description": "The favorite flag to store for a project."
      },
      "SubmitControllerCommandResponse": {
        "required": [
          "controllerId",
          "type",
          "instructionCount",
          "acceptedInstructionCount",
          "writes",
          "acceptedAtUtc",
          "deliveryWindowSeconds"
        ],
        "type": "object",
        "properties": {
          "controllerId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The controller the command was sent to.",
            "format": "int64"
          },
          "type": {
            "description": "The command type that was sent, as it was requested.",
            "$ref": "#/components/schemas/ControllerCommandType"
          },
          "instructionCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many register writes the command became — a composite command is several.",
            "format": "int32"
          },
          "acceptedInstructionCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many of them the delivery service accepted; equals instructionCount on this response.",
            "format": "int32"
          },
          "writes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControllerCommandWriteResponse"
            },
            "description": "The register writes, in the order they were sent: the event number (the register\naddress the realtime hub reports under) and the value written. A client watching the hub\ncan treat the same event arriving with the same value as the device's echo."
          },
          "acceptedAtUtc": {
            "type": "string",
            "description": "When the delivery service accepted the writes.",
            "format": "date-time"
          },
          "deliveryWindowSeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How many seconds the delivery service keeps trying to reach the controller before discarding the writes.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "The delivery service accepted the command. Accepted means the writes are queued for\ndelivery to the controller within the window — not that the controller has acted. Observe\nthe effect through the controller's state (GET /api/v1/controllers/{controllerId}, the\nstates refresh, or the realtime hub); the writes say which registers to watch there."
      },
      "UnregisterPushInstallationRequest": {
        "type": "object",
        "properties": {
          "platform": {
            "$ref": "#/components/schemas/PushPlatform"
          },
          "firebaseAppId": {
            "type": "string"
          },
          "registrationToken": {
            "type": "string"
          }
        },
        "description": "Removes the authenticated caller's subscription for one Firebase installation. The\ninstallation ID is write-only and is never returned or logged."
      },
      "UpdateServiceCallRequest": {
        "required": [
          "statusCode",
          "faultEquipmentCode",
          "faultDescription"
        ],
        "type": "object",
        "properties": {
          "statusCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Where the call now stands, from the status list in GET /api/v1/service-calls/vocabulary.\nMoving a call to a finished status does not record a closing date — see the API contract.",
            "format": "int32"
          },
          "faultEquipmentCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "What is faulty, from the fault equipment list in the vocabulary.",
            "format": "int32"
          },
          "faultDescription": {
            "type": "string",
            "description": "What is wrong. At most 250 characters."
          },
          "priority": {
            "description": "How urgently the call should be handled.",
            "$ref": "#/components/schemas/ServiceCallPriority"
          },
          "assignedTechnicianId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "The technician holding the call, from the technicians in the vocabulary. Send null to leave\nit unassigned — the previous assignment is not kept.",
            "format": "int64"
          },
          "notesForTechnician": {
            "type": [
              "null",
              "string"
            ],
            "description": "Instructions for whoever handles the call. At most 100 characters."
          },
          "projectId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Work in another project this user is authorized to work in — a customerId from\nGET /api/v1/auth/projects. Omit it to use the project the access token was issued for.",
            "format": "int64"
          }
        },
        "description": "The complete triage state to store on a call. Every member is written, so this replaces\nrather than patches: send the current values for anything that should stay as it is."
      },
      "UpsertedPushSubscriptionEventItemResponse": {
        "required": [
          "source",
          "modelCode",
          "eventNumber"
        ],
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        },
        "description": "A server-approved event selector stored with a notification subscription."
      },
      "UpsertPushSubscriptionEventRequest": {
        "required": [
          "source",
          "modelCode",
          "eventNumber"
        ],
        "type": "object",
        "properties": {
          "source": {
            "description": "Which stream an event came from. Crosses both the hub and REST as the name below.",
            "$ref": "#/components/schemas/ControllerEventSource"
          },
          "modelCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "eventNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        },
        "description": "One event selector for a notification subscription in specific-events mode."
      },
      "UpsertPushSubscriptionRequest": {
        "type": "object",
        "properties": {
          "platform": {
            "$ref": "#/components/schemas/PushPlatform"
          },
          "firebaseAppId": {
            "type": "string"
          },
          "registrationToken": {
            "type": "string"
          },
          "mode": {
            "$ref": "#/components/schemas/PushSubscriptionMode"
          },
          "scope": {
            "description": "Selects controllers for notifications: `authorized` (default) uses every\ncontroller the bearer token currently grants, while `explicit` uses the ids below.\nThe authorized set is saved at registration time and is refreshed by another upsert.",
            "examples": [
              "authorized"
            ],
            "$ref": "#/components/schemas/PushControllerScope"
          },
          "controllerIds": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            },
            "description": "Controller ids for `explicit` scope: 1-1000 positive, unique ids. This must be\nempty for `authorized` scope.",
            "example": [
              17537,
              27816
            ]
          },
          "eventKeys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpsertPushSubscriptionEventRequest"
            }
          }
        },
        "description": "Creates or updates the authenticated caller's notification subscription for one Firebase\ninstallation. The installation ID is write-only and is never returned or logged."
      },
      "UpsertPushSubscriptionResponse": {
        "required": [
          "id",
          "platform",
          "firebaseAppId",
          "mode",
          "isEnabled",
          "controllerIds",
          "eventKeys",
          "createdAtUtc",
          "updatedAtUtc",
          "deactivatedAtUtc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "platform": {
            "type": "string"
          },
          "firebaseAppId": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "isEnabled": {
            "type": "boolean"
          },
          "controllerIds": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int64"
            }
          },
          "eventKeys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpsertedPushSubscriptionEventItemResponse"
            }
          },
          "createdAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAtUtc": {
            "type": "string",
            "format": "date-time"
          },
          "deactivatedAtUtc": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        },
        "description": "The persisted notification subscription. Installation identifiers are omitted."
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "http",
        "description": "Short-lived RECOM access token.",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "tags": [
    {
      "name": "Authentication"
    },
    {
      "name": "Controllers"
    },
    {
      "name": "Push subscriptions"
    },
    {
      "name": "Service calls"
    },
    {
      "name": "Assistant"
    },
    {
      "name": "Controller commands"
    },
    {
      "name": "Logs"
    }
  ],
  "x-controller-vocabularies": {
    "kinds": [
      {
        "token": "boolean",
        "label": "boolean",
        "meaning": "A true or false fact the device reports."
      },
      {
        "token": "number",
        "label": "number",
        "meaning": "A numeric measurement, or a raw device number."
      },
      {
        "token": "count",
        "label": "count",
        "meaning": "How many of something there are."
      },
      {
        "token": "codedState",
        "label": "codedState",
        "meaning": "A raw device code together with the vocabulary name for it, so a code outside the confirmed vocabulary survives with a null name rather than being lost."
      },
      {
        "token": "measuredValue",
        "label": "measuredValue",
        "meaning": "A number travelling with its own unit, because a device mode decides which unit it is in."
      },
      {
        "token": "clock",
        "label": "clock",
        "meaning": "A time of day the device keeps itself."
      },
      {
        "token": "calendar",
        "label": "calendar",
        "meaning": "A calendar value the device packs into one register and this contract splits, so nobody re-splits it."
      },
      {
        "token": "version",
        "label": "version",
        "meaning": "A version number together with what it is a version of, which varies by model."
      },
      {
        "token": "enum",
        "label": "enum",
        "meaning": "One name from a closed set the contract publishes."
      },
      {
        "token": "collection",
        "label": "collection",
        "meaning": "Several values of one kind, such as the valve numbers a bitmap reports."
      },
      {
        "token": "objectGroup",
        "label": "objectGroup",
        "meaning": "A group that organizes related values; it carries no device value of its own."
      },
      {
        "token": "timestamp",
        "label": "timestamp",
        "meaning": "An instant recorded with the snapshot rather than reported by the device."
      }
    ],
    "origins": [
      {
        "token": "register",
        "label": "one register",
        "meaning": "Read straight out of one device register."
      },
      {
        "token": "registerBit",
        "label": "one register bit",
        "meaning": "Read from a single bit of one register; bit numbers here count from zero."
      },
      {
        "token": "registerPair",
        "label": "register pair",
        "meaning": "Joined from two registers — a low word and a high word — into one value larger than a register can hold."
      },
      {
        "token": "packedRegister",
        "label": "packed register",
        "meaning": "Unpacked from a register that carries several unrelated fields at once."
      },
      {
        "token": "derived",
        "label": "derived",
        "meaning": "Worked out from more than one device value, or from a device value and its configuration."
      },
      {
        "token": "apiPresentation",
        "label": "formatted by the API",
        "meaning": "The API decided this value's published form rather than reading it as it stands: a device number rendered as a time, a version paired with what it versions, or the model discriminator, which no register carries at all. The fact is still the device's wherever one is behind it — only the shape is the API's."
      },
      {
        "token": "snapshotMetadata",
        "label": "snapshot metadata",
        "meaning": "Recorded alongside the snapshot rather than reported in the register array."
      },
      {
        "token": "structure",
        "label": "group",
        "meaning": "A group or collection that holds other values rather than a value of its own."
      }
    ],
    "units": [
      {
        "token": "none",
        "label": "none",
        "meaning": "The value is dimensionless: it has no unit, rather than an unknown one."
      },
      {
        "token": "modeDependent",
        "label": "modeDependent",
        "meaning": "A sibling device register decides the unit; the value names which one."
      },
      {
        "token": "unconfirmed",
        "label": "unconfirmed",
        "meaning": "The value is confirmed and its unit is not: no inspected source names one, so the number is published exactly as the device reports it rather than scaled by a guess."
      }
    ],
    "commandEffects": [
      {
        "token": "latch",
        "label": "latch",
        "meaning": "Drives a command bit. Every latch carries the same value, so the address alone says what is being done."
      },
      {
        "token": "reset",
        "label": "reset",
        "meaning": "Zeroes an accumulating total. A 32-bit total clears both of its words."
      },
      {
        "token": "setPoint",
        "label": "set point",
        "meaning": "Writes a number into a configuration or countdown register."
      },
      {
        "token": "composite",
        "label": "composite",
        "meaning": "Several writes that are one operation; sending part of it leaves a state the product cannot name."
      },
      {
        "token": "noRegisterWrite",
        "label": "no register write",
        "meaning": "Travels as a command in the reference product and addresses no register at all."
      },
      {
        "token": "flag",
        "label": "flag",
        "meaning": "Writes a configuration bit, where the value is the instruction: one turns the behaviour on and zero turns it off."
      }
    ],
    "commandScopes": [
      {
        "token": "controller",
        "label": "controller",
        "meaning": "Aimed at the controller itself; one address and no target number."
      },
      {
        "token": "valve",
        "label": "valve",
        "meaning": "Aimed at one irrigation valve, numbered from one by its hardware port."
      },
      {
        "token": "program",
        "label": "program",
        "meaning": "Aimed at one irrigation program, named by the valve it starts with."
      },
      {
        "token": "gate",
        "label": "gate",
        "meaning": "Aimed at one dam gate, numbered from one."
      },
      {
        "token": "circuit",
        "label": "circuit",
        "meaning": "Aimed at one lighting circuit."
      }
    ],
    "commandEvidence": [
      {
        "token": "published",
        "label": "published",
        "meaning": "Two independent sources agree on the address and on what it does."
      },
      {
        "token": "confirmedNotPublished",
        "label": "confirmed, not published",
        "meaning": "Understood and evidenced, and deliberately outside the surface built on today."
      },
      {
        "token": "contradicted",
        "label": "contradicted",
        "meaning": "The sources disagree; the disagreement is recorded rather than resolved without a device probe."
      },
      {
        "token": "unconfirmed",
        "label": "unconfirmed",
        "meaning": "One source only, or none that names it. Never sent: a guessed command writes a real register on real hardware."
      },
      {
        "token": "notCommand",
        "label": "not a command",
        "meaning": "Travels as a command in the reference product and resolves no register address. Not a gap evidence could close."
      }
    ]
  },
  "x-controller-commands": {
    "DM": [
      {
        "name": "clearAlarms",
        "summary": "Clears the controller's alarms.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "dm.clear-alarms",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1501,
            "registerNumber": 42,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q01",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1501,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setGateRemoteControl",
        "summary": "Enables or disables remote control of one gate.",
        "effect": "latch",
        "scope": "gate",
        "evidence": "dm.gate-remote",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 4,
        "preconditions": [
          "No intent reaches this yet: the dam model has no encoder path."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1517,
            "registerNumber": 43,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q17",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 4,
            "eventNumber": 1565,
            "registerNumber": 46,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1517,
            "value": "<value>",
            "purpose": "One to enable remote control of the gate, zero to disable it.",
            "targetStride": 16
          }
        ]
      },
      {
        "name": "openGate",
        "summary": "Opens one gate.",
        "effect": "latch",
        "scope": "gate",
        "evidence": "dm.gate-open",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 4,
        "preconditions": [
          "No intent reaches this yet: the dam model has no encoder path."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1518,
            "registerNumber": 43,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q18",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 4,
            "eventNumber": 1566,
            "registerNumber": 46,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q66",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1518,
            "value": "1",
            "purpose": "Drives the gate's open latch.",
            "targetStride": 16
          }
        ]
      },
      {
        "name": "closeGate",
        "summary": "Closes one gate.",
        "effect": "latch",
        "scope": "gate",
        "evidence": "dm.gate-close",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 4,
        "preconditions": [
          "No intent reaches this yet: the dam model has no encoder path."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1519,
            "registerNumber": 43,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q19",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 4,
            "eventNumber": 1567,
            "registerNumber": 46,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q67",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1519,
            "value": "1",
            "purpose": "Drives the gate's close latch.",
            "targetStride": 16
          }
        ]
      }
    ],
    "I1": [
      {
        "name": "openValveManually",
        "summary": "Opens one valve by hand, outside any program.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.manual-valve",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "The valve is not already open by hand."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1565,
            "registerNumber": 20,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1565,
            "registerNumber": 46,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1580,
            "registerNumber": 20,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q80",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1580,
            "registerNumber": 46,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q80",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1565,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "closeValveManually",
        "summary": "Closes a hand-opened valve.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.manual-valve",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "The valve is currently open by hand.",
          "RECOM also closes the master valve when no other valve remains open — its own policy, not the reference's."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1581,
            "registerNumber": 21,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q81",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1581,
            "registerNumber": 47,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q81",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1596,
            "registerNumber": 21,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q96",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1596,
            "registerNumber": 47,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q96",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1581,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "openMasterValve",
        "summary": "Opens the master valve, which occupies the board's last hardware port.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.master-valve",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "A master valve is fitted.",
          "Its port is the board's hardware port count."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1565,
            "registerNumber": 20,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1565,
            "registerNumber": 46,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1580,
            "registerNumber": 20,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q80",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1580,
            "registerNumber": 46,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q80",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1565,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "closeMasterValve",
        "summary": "Closes the master valve.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.master-valve",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "A master valve is fitted."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1581,
            "registerNumber": 21,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q81",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1581,
            "registerNumber": 47,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q81",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1596,
            "registerNumber": 21,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q96",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1596,
            "registerNumber": 47,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q96",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1581,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "openFilterValve",
        "summary": "Opens the filter valve.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.filter-valve",
        "evidenceStatus": "contradicted",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "A filter is fitted.",
          "On a fixed-port board the filter's port derives from the hardware port count, less the master and fertilizer valves where those are fitted; otherwise it follows the last active valve."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1565,
            "registerNumber": 20,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1565,
            "registerNumber": 46,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q65",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1580,
            "registerNumber": 20,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q80",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1580,
            "registerNumber": 46,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q80",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1565,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "closeFilterValve",
        "summary": "Closes the filter valve.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.filter-valve",
        "evidenceStatus": "contradicted",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "A filter is fitted."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1581,
            "registerNumber": 21,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q81",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1581,
            "registerNumber": 47,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q81",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1596,
            "registerNumber": 21,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q96",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1596,
            "registerNumber": 47,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q96",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1581,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "startValveFullProgram",
        "summary": "Starts the program with valve chaining — starting a valve after another has finished irrigating — and fertilization enabled.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.valve-start",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 3317,
            "registerNumber": 23,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿17",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 3317,
            "registerNumber": 49,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿17",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 3332,
            "registerNumber": 23,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿32",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 3332,
            "registerNumber": 49,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿32",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 3317,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "startValveWithFertilizerUnchained",
        "summary": "Runs a valve fertilized, stopping at this valve rather than continuing into the ones that follow it.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.valve-start",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "preconditions": [
          "A fertilizer valve is fitted."
        ],
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 3333,
            "registerNumber": 24,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿33",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 3333,
            "registerNumber": 50,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿33",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 3348,
            "registerNumber": 24,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿48",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 3348,
            "registerNumber": 50,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿48",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 3333,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "startValveChainedWithoutFertilizer",
        "summary": "Runs a valve unfertilized, continuing into the valves that follow it in its program. Named by the product's event table; no reference client sends it.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.valve-start",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 3349,
            "registerNumber": 25,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿49",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 3349,
            "registerNumber": 51,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿49",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 3364,
            "registerNumber": 25,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿64",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 3364,
            "registerNumber": 51,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿64",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 3349,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "startValvePlainUnchained",
        "summary": "Runs a valve unfertilized, stopping at this valve. The address the reference client's plain open-valve command sends.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.valve-start",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 3365,
            "registerNumber": 26,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿65",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 3365,
            "registerNumber": 52,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿65",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 3380,
            "registerNumber": 26,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿80",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 3380,
            "registerNumber": 52,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿80",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 3365,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "stopValve",
        "summary": "Stops a valve and its program. One address, reached from both close-valve and end-program in the reference: they are the same instruction.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.valve-stop",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 3381,
            "registerNumber": 27,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿81",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 3381,
            "registerNumber": 53,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿81",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 3396,
            "registerNumber": 27,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿96",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 3396,
            "registerNumber": 53,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿96",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 3381,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetValveError",
        "summary": "Clears one valve's error state.",
        "effect": "latch",
        "scope": "valve",
        "evidence": "i1.valve-reset-error",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 3301,
            "registerNumber": 22,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿01",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 3301,
            "registerNumber": 48,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "¿01",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 3316,
            "registerNumber": 22,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿16",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 3316,
            "registerNumber": 48,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "¿16",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 3301,
            "value": "1",
            "purpose": "Drives the valve's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "freezeController",
        "summary": "Takes a fixed-port board out of service. The reference sends this latch alone, and explicitly does not pair it with the out-of-service latch below.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "i1.service-state",
        "evidenceStatus": "contradicted",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1501,
            "registerNumber": 42,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q01",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1501,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "takeControllerOutOfService",
        "summary": "Takes a short-layout board out of service. The reference sends this latch alone and does not freeze the controller first.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "i1.service-state",
        "evidenceStatus": "contradicted",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1506,
            "registerNumber": 16,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q06",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1506,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "unfreezeController",
        "summary": "Returns a fixed-port board to service.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "i1.service-state",
        "evidenceStatus": "contradicted",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1502,
            "registerNumber": 42,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q02",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1502,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "returnControllerToService",
        "summary": "Returns a short-layout board to service: the unfreeze latch, then the in-service latch. One operation — sending half of it leaves a state the product has no name for.",
        "effect": "composite",
        "scope": "controller",
        "evidence": "i1.service-state",
        "evidenceStatus": "contradicted",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1502,
            "registerNumber": 16,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q02",
            "value": "1"
          },
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1507,
            "registerNumber": 16,
            "bitIndex": 6,
            "registerKind": "SetBit",
            "methodCode": "q07",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1502,
            "value": "1",
            "purpose": "Unfreezes the controller.",
            "targetStride": 1
          },
          {
            "firstEventNumber": 1507,
            "value": "1",
            "purpose": "Returns it to service.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetControllerErrors",
        "summary": "Clears the controller's error state.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "i1.reset-errors",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1504,
            "registerNumber": 16,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q04",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1504,
            "registerNumber": 42,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q04",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1504,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "restartSystems",
        "summary": "Restarts the controller's systems. It does not clear runtime data, which is what this address was named for until 2026-09-06.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "i1.restart-systems",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1505,
            "registerNumber": 16,
            "bitIndex": 4,
            "registerKind": "SetBit",
            "methodCode": "q05",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1505,
            "registerNumber": 42,
            "bitIndex": 4,
            "registerKind": "SetBit",
            "methodCode": "q05",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1505,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "restartController",
        "summary": "Restarts the controller.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "i1.restart",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1801,
            "registerNumber": 79,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L01",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1801,
            "registerNumber": 450,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L01",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1801,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetTotalIrrigation",
        "summary": "Zeroes the controller's total irrigation.",
        "effect": "composite",
        "scope": "controller",
        "evidence": "i1.controller-accumulators",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1901,
            "registerNumber": 475,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R01",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1902,
            "registerNumber": 476,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R02",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1901,
            "registerNumber": 846,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R01",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1902,
            "registerNumber": 847,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R02",
            "value": "0"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1901,
            "value": "0",
            "purpose": "Zeroes the total's low word.",
            "targetStride": 1
          },
          {
            "firstEventNumber": 1902,
            "value": "0",
            "purpose": "Zeroes its high word.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetTotalWaterLeak",
        "summary": "Zeroes the controller's total water leak.",
        "effect": "composite",
        "scope": "controller",
        "evidence": "i1.controller-accumulators",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1903,
            "registerNumber": 477,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R03",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1904,
            "registerNumber": 478,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R04",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1903,
            "registerNumber": 848,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R03",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1904,
            "registerNumber": 849,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R04",
            "value": "0"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1903,
            "value": "0",
            "purpose": "Zeroes the total's low word.",
            "targetStride": 1
          },
          {
            "firstEventNumber": 1904,
            "value": "0",
            "purpose": "Zeroes its high word.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetTotalFertilizerLeak",
        "summary": "Zeroes the controller's total fertilizer leak.",
        "effect": "composite",
        "scope": "controller",
        "evidence": "i1.controller-accumulators",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1905,
            "registerNumber": 479,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R05",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1906,
            "registerNumber": 480,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R06",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1905,
            "registerNumber": 850,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R05",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1906,
            "registerNumber": 851,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R06",
            "value": "0"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1905,
            "value": "0",
            "purpose": "Zeroes the total's low word.",
            "targetStride": 1
          },
          {
            "firstEventNumber": 1906,
            "value": "0",
            "purpose": "Zeroes its high word.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetTotalRinses",
        "summary": "Zeroes the controller's rinse counter, a single register rather than a pair.",
        "effect": "reset",
        "scope": "controller",
        "evidence": "i1.controller-accumulators",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1908,
            "registerNumber": 482,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R08",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1908,
            "registerNumber": 853,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R08",
            "value": "0"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1908,
            "value": "0",
            "purpose": "Zeroes the counter.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "resetValveTotalIrrigation",
        "summary": "Zeroes one valve's total irrigation.",
        "effect": "composite",
        "scope": "valve",
        "evidence": "i1.valve-accumulators",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1910,
            "registerNumber": 484,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R10",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1911,
            "registerNumber": 485,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R11",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1910,
            "registerNumber": 855,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R10",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1911,
            "registerNumber": 856,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R11",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1940,
            "registerNumber": 514,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R40",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1941,
            "registerNumber": 515,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R41",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1940,
            "registerNumber": 885,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R40",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1941,
            "registerNumber": 886,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R41",
            "value": "0"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1910,
            "value": "0",
            "purpose": "Zeroes the valve total's low word.",
            "targetStride": 2
          },
          {
            "firstEventNumber": 1911,
            "value": "0",
            "purpose": "Zeroes its high word.",
            "targetStride": 2
          }
        ]
      },
      {
        "name": "resetValveTotalFertilizer",
        "summary": "Zeroes one valve's total fertilizer. The contiguous continuation of the irrigation totals, same stride and no overlap.",
        "effect": "composite",
        "scope": "valve",
        "evidence": "i1.valve-accumulators",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1942,
            "registerNumber": 516,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R42",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1943,
            "registerNumber": 517,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R43",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1942,
            "registerNumber": 887,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R42",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1943,
            "registerNumber": 888,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R43",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1972,
            "registerNumber": 546,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R72",
            "value": "0"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1973,
            "registerNumber": 547,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R73",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1972,
            "registerNumber": 917,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R72",
            "value": "0"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1973,
            "registerNumber": 918,
            "bitIndex": 0,
            "registerKind": "Accumulator",
            "methodCode": "R73",
            "value": "0"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1942,
            "value": "0",
            "purpose": "Zeroes the valve total's low word.",
            "targetStride": 2
          },
          {
            "firstEventNumber": 1943,
            "value": "0",
            "purpose": "Zeroes its high word.",
            "targetStride": 2
          }
        ]
      },
      {
        "name": "setRemainingValveAmount",
        "summary": "Overwrites a valve's remaining irrigation amount. The same address a start's duration override writes.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.remaining-state",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "modeDependent",
        "encoding": "Raw register value, in the unit the valve's own method bit selects.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1836,
            "registerNumber": 114,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L36",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1836,
            "registerNumber": 485,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L36",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1851,
            "registerNumber": 129,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L51",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1851,
            "registerNumber": 500,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L51",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1836,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRemainingValveFertilizerAmount",
        "summary": "Overwrites a valve's remaining fertilizer amount.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.remaining-state",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "modeDependent",
        "encoding": "Raw register value, in the unit the valve's own method bit selects.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1852,
            "registerNumber": 130,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L52",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1852,
            "registerNumber": 501,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L52",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1867,
            "registerNumber": 145,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L67",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1867,
            "registerNumber": 516,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L67",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1852,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRemainingValvePulseCount",
        "summary": "Overwrites a valve's remaining pulse count.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.remaining-state",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1804,
            "registerNumber": 82,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L04",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1804,
            "registerNumber": 453,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L04",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1819,
            "registerNumber": 97,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L19",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1819,
            "registerNumber": 468,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L19",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1804,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRemainingValvePulseInterval",
        "summary": "Overwrites a valve's remaining pulse interval.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.remaining-state",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "minutes",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1820,
            "registerNumber": 98,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L20",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1820,
            "registerNumber": 469,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L20",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1835,
            "registerNumber": 113,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L35",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1835,
            "registerNumber": 484,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L35",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1820,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRemainingMinutesBetweenIrrigationCycles",
        "summary": "Overwrites the minutes remaining before the next irrigation cycle.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.remaining-state",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "minutes",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2401,
            "registerNumber": 277,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ01",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2401,
            "registerNumber": 648,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ01",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2401,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRemainingRinseTime",
        "summary": "Overwrites the time remaining in the running rinse.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.remaining-state",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "minutes",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2403,
            "registerNumber": 279,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ03",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2403,
            "registerNumber": 650,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ03",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2403,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveEnabledBitmap",
        "summary": "Enables or disables valves. One register carrying the whole valve set, with no per-valve offset — the value names which valves.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.disable-valve",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2517,
            "registerNumber": 392,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ17",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2517,
            "registerNumber": 763,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ17",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2517,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setActiveValveCount",
        "summary": "Sets how many valves the controller runs. Not an isolated write: it also moves the filter valve's port on boards that place the filter after the last active valve.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.active-valve-count",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2514,
            "registerNumber": 389,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ14",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2514,
            "registerNumber": 760,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ14",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2514,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setMainValveDelaySeconds",
        "summary": "Sets the master valve's suspend delay.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "seconds",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2502,
            "registerNumber": 377,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ02",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2502,
            "registerNumber": 748,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ02",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2502,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setWaterMeterLitresPerPulse",
        "summary": "Sets the water meter's litres-per-pulse ratio.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "litres",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2503,
            "registerNumber": 378,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ03",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2503,
            "registerNumber": 749,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ03",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2503,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setMinutesBetweenRinses",
        "summary": "Sets the configured interval between rinses — a different register from the remaining countdown above, which the reference's command names confuse.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2507,
            "registerNumber": 382,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ07",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2507,
            "registerNumber": 753,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ07",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2507,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRinseDurationSeconds",
        "summary": "Sets the configured rinse duration.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "seconds",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2509,
            "registerNumber": 384,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ09",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2509,
            "registerNumber": 755,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ09",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2509,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setAutoNominalFlowChangePercent",
        "summary": "Sets the percentage by which an automatic nominal-flow update may move.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "percent",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1802,
            "registerNumber": 80,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L02",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1802,
            "registerNumber": 451,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L02",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1802,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveAmount",
        "summary": "Sets a valve's configured irrigation amount.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "modeDependent",
        "encoding": "Volume amounts are written as cubic metres multiplied by a hundred; timed amounts are written raw, in the unit the valve's method bit selects.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2436,
            "registerNumber": 312,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ36",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2436,
            "registerNumber": 683,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ36",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2451,
            "registerNumber": 327,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ51",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2451,
            "registerNumber": 698,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ51",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2436,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveFertilizerAmount",
        "summary": "Sets a valve's configured fertilizer amount.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "cubicMetres",
        "encoding": "Cubic metres multiplied by a hundred.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2484,
            "registerNumber": 360,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ84",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2484,
            "registerNumber": 731,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ84",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2499,
            "registerNumber": 375,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ99",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2499,
            "registerNumber": 746,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ99",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2484,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveFlowMinimum",
        "summary": "Sets a valve's minimum flow.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "cubicMetresPerHour",
        "encoding": "Cubic metres per hour multiplied by a hundred.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2303,
            "registerNumber": 180,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג03",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2303,
            "registerNumber": 551,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג03",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2318,
            "registerNumber": 195,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג18",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2318,
            "registerNumber": 566,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג18",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2303,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveFlowNominal",
        "summary": "Sets a valve's nominal flow.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "cubicMetresPerHour",
        "encoding": "Cubic metres per hour multiplied by a hundred.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2319,
            "registerNumber": 196,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג19",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2319,
            "registerNumber": 567,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג19",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2334,
            "registerNumber": 211,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג34",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2334,
            "registerNumber": 582,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג34",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2319,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveFlowMaximum",
        "summary": "Sets a valve's maximum flow.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "cubicMetresPerHour",
        "encoding": "Cubic metres per hour multiplied by a hundred.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2335,
            "registerNumber": 212,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג35",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2335,
            "registerNumber": 583,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג35",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2350,
            "registerNumber": 227,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג50",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2350,
            "registerNumber": 598,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג50",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2335,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveIrrigationDays",
        "summary": "Sets which days a valve irrigates.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "Sunday-first weekday bitmap. Zero means the valve is scheduled by another valve; 32639 is a full week for a follower.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2367,
            "registerNumber": 244,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג67",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2367,
            "registerNumber": 615,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג67",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2382,
            "registerNumber": 259,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג82",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2382,
            "registerNumber": 630,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג82",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2367,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveStartTime",
        "summary": "Sets a valve's start time.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "Minutes from midnight.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2383,
            "registerNumber": 260,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג83",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2383,
            "registerNumber": 631,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג83",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2398,
            "registerNumber": 275,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג98",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2398,
            "registerNumber": 646,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג98",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2383,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveFillTime",
        "summary": "Sets a valve's pipe fill time.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1884,
            "registerNumber": 162,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L84",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1884,
            "registerNumber": 533,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L84",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1899,
            "registerNumber": 177,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L99",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1899,
            "registerNumber": 548,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "L99",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1884,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveStartAfterValve",
        "summary": "Sets which valve this one follows.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2404,
            "registerNumber": 280,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ04",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2404,
            "registerNumber": 651,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ04",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2419,
            "registerNumber": 295,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ19",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2419,
            "registerNumber": 666,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ19",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2404,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveGroup",
        "summary": "Sets which valves run together with this one.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "Valve bitmap.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2420,
            "registerNumber": 296,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ20",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2420,
            "registerNumber": 667,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ20",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2435,
            "registerNumber": 311,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ35",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2435,
            "registerNumber": 682,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ35",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2420,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValvePulseCount",
        "summary": "Sets a valve's configured pulse count.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2520,
            "registerNumber": 395,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ20",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2520,
            "registerNumber": 766,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ20",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2535,
            "registerNumber": 410,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ35",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2535,
            "registerNumber": 781,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ35",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2520,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValvePulseInterval",
        "summary": "Sets a valve's configured pulse interval.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2536,
            "registerNumber": 411,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ36",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2536,
            "registerNumber": 782,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ36",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2551,
            "registerNumber": 426,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ51",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2551,
            "registerNumber": 797,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ51",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2536,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveLowFlowAlarmDelay",
        "summary": "Sets a valve's low-flow alarm delay.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2552,
            "registerNumber": 427,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ52",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2552,
            "registerNumber": 798,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ52",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2567,
            "registerNumber": 442,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ67",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2567,
            "registerNumber": 813,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ67",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2552,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveHighFlowAlarmDelay",
        "summary": "Sets a valve's high-flow alarm delay.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2568,
            "registerNumber": 443,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ68",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2568,
            "registerNumber": 814,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ68",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2583,
            "registerNumber": 458,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ83",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2583,
            "registerNumber": 829,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ83",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2568,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveIrrigationFactorPercent",
        "summary": "Sets a valve's irrigation change percentage.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "percent",
        "encoding": "raw",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2584,
            "registerNumber": 459,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ84",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2584,
            "registerNumber": 830,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ84",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2599,
            "registerNumber": 474,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ99",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2599,
            "registerNumber": 845,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ99",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2584,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setMasterValveFitted",
        "summary": "Records that a master valve is fitted. It also decides where the filter valve sits on a fixed-port board.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1517,
            "registerNumber": 17,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q17",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1517,
            "registerNumber": 43,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q17",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1517,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setFertilizerFitted",
        "summary": "Records that a fertilizer valve is fitted.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1518,
            "registerNumber": 17,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q18",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1518,
            "registerNumber": 43,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q18",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1518,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setPulseIrrigationAllowed",
        "summary": "Allows pulsed irrigation.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1519,
            "registerNumber": 17,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q19",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1519,
            "registerNumber": 43,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q19",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1519,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRinsingBlockedWhilePipesFill",
        "summary": "Blocks rinsing while the pipes are filling.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1522,
            "registerNumber": 17,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q22",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1522,
            "registerNumber": 43,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q22",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1522,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setFertilizerMeasuredByTime",
        "summary": "Measures fertilizer by time rather than by volume.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1523,
            "registerNumber": 17,
            "bitIndex": 6,
            "registerKind": "SetBit",
            "methodCode": "q23",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1523,
            "registerNumber": 43,
            "bitIndex": 6,
            "registerKind": "SetBit",
            "methodCode": "q23",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1523,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setFertilizerProportional",
        "summary": "Doses fertilizer in proportion to the water.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1524,
            "registerNumber": 17,
            "bitIndex": 7,
            "registerKind": "SetBit",
            "methodCode": "q24",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1524,
            "registerNumber": 43,
            "bitIndex": 7,
            "registerKind": "SetBit",
            "methodCode": "q24",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1524,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setIrrigationBlockedWhileRinsing",
        "summary": "Blocks irrigation while a rinse is running.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1533,
            "registerNumber": 18,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q33",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1533,
            "registerNumber": 44,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q33",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1533,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setRinsingWaterOnly",
        "summary": "Rinses with water only, never with fertilizer.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1534,
            "registerNumber": 18,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q34",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1534,
            "registerNumber": 44,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q34",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1534,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setIrrigationContinuesAfterFertilizer",
        "summary": "Continues irrigating after the fertilizer dose finishes.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1535,
            "registerNumber": 18,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q35",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1535,
            "registerNumber": 44,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q35",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1535,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setMasterValveOpensBeforeValves",
        "summary": "Opens the master valve ahead of the irrigation valves.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1536,
            "registerNumber": 18,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q36",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1536,
            "registerNumber": 44,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q36",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1536,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setMasterValveClosesAfterValves",
        "summary": "Closes the master valve after the irrigation valves.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1537,
            "registerNumber": 18,
            "bitIndex": 4,
            "registerKind": "SetBit",
            "methodCode": "q37",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1537,
            "registerNumber": 44,
            "bitIndex": 4,
            "registerKind": "SetBit",
            "methodCode": "q37",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1537,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setIrrigationStopsOnFault",
        "summary": "Stops irrigation when the controller reports a fault.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1538,
            "registerNumber": 18,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q38",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1538,
            "registerNumber": 44,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q38",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1538,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setGroupIrrigationAllowed",
        "summary": "Allows several valves to irrigate as a group.",
        "effect": "flag",
        "scope": "controller",
        "evidence": "i1.behaviour-flags",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One to turn the behaviour on, zero to turn it off.",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1540,
            "registerNumber": 18,
            "bitIndex": 7,
            "registerKind": "SetBit",
            "methodCode": "q40",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1540,
            "registerNumber": 44,
            "bitIndex": 7,
            "registerKind": "SetBit",
            "methodCode": "q40",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1540,
            "value": "<value>",
            "purpose": "Writes the behaviour bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setHighFlowBehaviour",
        "summary": "Sets what the controller does when flow runs high.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2518,
            "registerNumber": 393,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ18",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2518,
            "registerNumber": 764,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ18",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2518,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setFertilizerMeterLitresPerPulse",
        "summary": "Sets the fertilizer meter's litres-per-pulse ratio.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "litres",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2504,
            "registerNumber": 379,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ04",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2504,
            "registerNumber": 750,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ04",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2504,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setNoIrrigationTime",
        "summary": "Sets the window during which the controller does not irrigate.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2506,
            "registerNumber": 381,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ06",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2506,
            "registerNumber": 752,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ06",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2506,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setPulsesBeforeLeakReported",
        "summary": "Sets how many unexpected pulses count as a leak.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2511,
            "registerNumber": 386,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ11",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2511,
            "registerNumber": 757,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ11",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2511,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setFilterCount",
        "summary": "Sets how many filters the controller rinses.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2515,
            "registerNumber": 390,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ15",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2515,
            "registerNumber": 761,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ15",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2515,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setFlowMeasuredByTime",
        "summary": "Measures flow by time rather than by volume.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2519,
            "registerNumber": 394,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ19",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2519,
            "registerNumber": 765,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "פ19",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2519,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setMinutesBeforeNoPulsesReported",
        "summary": "Sets how long without a pulse counts as a stopped meter.",
        "effect": "setPoint",
        "scope": "controller",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "minutes",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2399,
            "registerNumber": 276,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג99",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2399,
            "registerNumber": 647,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "ג99",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2399,
            "value": "<value>",
            "purpose": "Writes the value into the controller's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveAmountBeforeFertilizer",
        "summary": "Sets the amount a valve irrigates before its fertilizer dose starts.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "modeDependent",
        "encoding": "Volume amounts are written as cubic metres multiplied by a hundred; timed amounts are written raw.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2452,
            "registerNumber": 328,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ52",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2452,
            "registerNumber": 699,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ52",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2467,
            "registerNumber": 343,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ67",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2467,
            "registerNumber": 714,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ67",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2452,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveAmountAfterFertilizer",
        "summary": "Sets the amount a valve irrigates after its fertilizer dose finishes.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "modeDependent",
        "encoding": "Volume amounts are written as cubic metres multiplied by a hundred; timed amounts are written raw.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 2468,
            "registerNumber": 344,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ68",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 2468,
            "registerNumber": 715,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ68",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 2483,
            "registerNumber": 359,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ83",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 2483,
            "registerNumber": 730,
            "bitIndex": 0,
            "registerKind": "SetPoint",
            "methodCode": "כ83",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 2468,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setValveIrrigationMethod",
        "summary": "Sets whether a valve measures its run by volume or by time.",
        "effect": "setPoint",
        "scope": "valve",
        "evidence": "i1.configuration",
        "evidenceStatus": "confirmedNotPublished",
        "sendable": false,
        "unit": "none",
        "encoding": "One bit per valve in a shared register; the value carries the method.",
        "highestTarget": 16,
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1549,
            "registerNumber": 19,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q49",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1549,
            "registerNumber": 45,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q49",
            "value": "<value>"
          },
          {
            "registerCount": 548,
            "targetNumber": 16,
            "eventNumber": 1564,
            "registerNumber": 19,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q64",
            "value": "<value>"
          },
          {
            "registerCount": 1066,
            "targetNumber": 16,
            "eventNumber": 1564,
            "registerNumber": 45,
            "bitIndex": 15,
            "registerKind": "SetBit",
            "methodCode": "q64",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1549,
            "value": "<value>",
            "purpose": "Writes the value into the valve's register.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "refreshControllerData",
        "summary": "The reference's forced refresh. Its method name resolves no register block and it is dropped before a transport message is built, so there is no forced-refresh command on current firmware.",
        "effect": "noRegisterWrite",
        "scope": "controller",
        "evidence": "i1.refresh",
        "evidenceStatus": "notCommand",
        "sendable": false,
        "unit": "none",
        "encoding": "raw"
      },
      {
        "name": "openOnlineWindow",
        "summary": "Opens a window during which the controller reports. Published as a separate go-online message on a different channel — a lease on the device's reporting, not a register write. It is the only thing that makes a controller report.",
        "effect": "noRegisterWrite",
        "scope": "controller",
        "evidence": "i1.online-window",
        "evidenceStatus": "notCommand",
        "sendable": false,
        "unit": "none",
        "encoding": "raw"
      },
      {
        "name": "switchToGsm",
        "summary": "Backdoor behaviour on a pseudo-block that names no register.",
        "effect": "noRegisterWrite",
        "scope": "controller",
        "evidence": "i1.go-gsm",
        "evidenceStatus": "notCommand",
        "sendable": false,
        "unit": "none",
        "encoding": "raw"
      }
    ],
    "IP": [
      {
        "name": "resetFlowAlarms",
        "summary": "Clears the flow alarms.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "ip.reset-errors",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1501,
            "registerNumber": 16,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q01",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1501,
            "registerNumber": 42,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q01",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1501,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setModeActive",
        "summary": "Puts the controller into its active working state.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "ip.operating-mode",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1502,
            "registerNumber": 16,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q02",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1502,
            "registerNumber": 42,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q02",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1502,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setModeInactiveOpen",
        "summary": "Neutralizes the controller, leaving the master valve open.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "ip.operating-mode",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1503,
            "registerNumber": 16,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q03",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1503,
            "registerNumber": 42,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q03",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1503,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setModeInactiveClosed",
        "summary": "Neutralizes the controller, leaving the master valve closed.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "ip.operating-mode",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1504,
            "registerNumber": 16,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q04",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1504,
            "registerNumber": 42,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q04",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1504,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "openMasterValve",
        "summary": "Opens the master valve. A dedicated address, unlike the irrigation controller's port-resolved master valve.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "ip.master-valve",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1505,
            "registerNumber": 16,
            "bitIndex": 4,
            "registerKind": "SetBit",
            "methodCode": "q05",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1505,
            "registerNumber": 42,
            "bitIndex": 4,
            "registerKind": "SetBit",
            "methodCode": "q05",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1505,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "closeMasterValve",
        "summary": "Closes the master valve.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "ip.master-valve",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          548,
          1066
        ],
        "addresses": [
          {
            "registerCount": 548,
            "targetNumber": 1,
            "eventNumber": 1506,
            "registerNumber": 16,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q06",
            "value": "1"
          },
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1506,
            "registerNumber": 42,
            "bitIndex": 5,
            "registerKind": "SetBit",
            "methodCode": "q06",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1506,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "refreshControllerData",
        "summary": "The same dropped refresh the irrigation controller carries.",
        "effect": "noRegisterWrite",
        "scope": "controller",
        "evidence": "ip.refresh",
        "evidenceStatus": "notCommand",
        "sendable": false,
        "unit": "none",
        "encoding": "raw"
      }
    ],
    "LT": [
      {
        "name": "clearAlarms",
        "summary": "Clears the cabinet's alarms.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.clear-alarms",
        "evidenceStatus": "published",
        "sendable": true,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1501,
            "registerNumber": 42,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q01",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1501,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setGeneratorRemoteControl",
        "summary": "Enables or disables remote control of the generator. One address driven with one or zero rather than two addresses.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.generator-remote",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "preconditions": [
          "No intent reaches this yet: the lighting models have no encoder path."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1549,
            "registerNumber": 45,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q49",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1549,
            "value": "<value>",
            "purpose": "One to enable remote control, zero to disable it.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "startGenerator",
        "summary": "Starts the generator.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.generator-run",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1550,
            "registerNumber": 45,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q50",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1550,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "stopGenerator",
        "summary": "Stops the generator.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.generator-run",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1551,
            "registerNumber": 45,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q51",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1551,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "emergencyStopGenerator",
        "summary": "Shuts the generator down immediately.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.generator-run",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1552,
            "registerNumber": 45,
            "bitIndex": 3,
            "registerKind": "SetBit",
            "methodCode": "q52",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1552,
            "value": "1",
            "purpose": "Drives the controller's command latch.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "setLightingRemoteControl",
        "summary": "Enables or disables remote control of the lighting. One address driven with one or zero, as the generator's is.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.lighting-switching",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "preconditions": [
          "No intent reaches this yet: the lighting models have no encoder path.",
          "The read-side event catalogue names this address differently; the state contract, not this declaration, is where that is resolved."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1517,
            "registerNumber": 43,
            "bitIndex": 0,
            "registerKind": "SetBit",
            "methodCode": "q17",
            "value": "<value>"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1517,
            "value": "<value>",
            "purpose": "One to hand the lighting to remote control, zero to take it back.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "switchLightingOn",
        "summary": "Switches the lighting on by hand.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.lighting-switching",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "preconditions": [
          "No intent reaches this yet: the lighting models have no encoder path.",
          "The read-side event catalogue names this address differently; the state contract, not this declaration, is where that is resolved."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1518,
            "registerNumber": 43,
            "bitIndex": 1,
            "registerKind": "SetBit",
            "methodCode": "q18",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1518,
            "value": "1",
            "purpose": "Drives the manual lighting-on bit.",
            "targetStride": 1
          }
        ]
      },
      {
        "name": "switchLightingOff",
        "summary": "Switches the lighting off by hand.",
        "effect": "latch",
        "scope": "controller",
        "evidence": "lt.lighting-switching",
        "evidenceStatus": "published",
        "sendable": false,
        "unit": "none",
        "encoding": "raw",
        "preconditions": [
          "No intent reaches this yet: the lighting models have no encoder path.",
          "The read-side event catalogue names this address differently; the state contract, not this declaration, is where that is resolved."
        ],
        "layouts": [
          1066
        ],
        "addresses": [
          {
            "registerCount": 1066,
            "targetNumber": 1,
            "eventNumber": 1519,
            "registerNumber": 43,
            "bitIndex": 2,
            "registerKind": "SetBit",
            "methodCode": "q19",
            "value": "1"
          }
        ],
        "steps": [
          {
            "firstEventNumber": 1519,
            "value": "1",
            "purpose": "Drives the manual lighting-off bit.",
            "targetStride": 1
          }
        ]
      }
    ],
    "WE": [
      {
        "name": "refreshControllerData",
        "summary": "The weather station's only reference method, and it is the same dropped refresh. The model accepts no commands.",
        "effect": "noRegisterWrite",
        "scope": "controller",
        "evidence": "we.refresh",
        "evidenceStatus": "notCommand",
        "sendable": false,
        "unit": "none",
        "encoding": "raw"
      }
    ]
  },
  "x-problem-catalog": [
    {
      "code": "assistant.answer_unavailable",
      "status": 502,
      "type": "https://recom.example/problems/assistant/answer-unavailable",
      "title": "Assistant produced no answer",
      "detail": "The assistant did not produce a usable answer for this question. Rephrase it or try again."
    },
    {
      "code": "assistant.model_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/assistant/model-unavailable",
      "title": "Assistant model temporarily unavailable",
      "detail": "The assistant model could not be reached. Try again shortly."
    },
    {
      "code": "auth.continuation_expired",
      "status": 401,
      "type": "https://recom.example/problems/auth/continuation-expired",
      "title": "Continuation expired",
      "detail": "Reauthentication with credentials is required."
    },
    {
      "code": "auth.forbidden",
      "status": 403,
      "type": "https://recom.example/problems/auth/forbidden",
      "title": "Not permitted",
      "detail": "The authenticated identity is not permitted to access this resource."
    },
    {
      "code": "auth.invalid_continuation_token",
      "status": 401,
      "type": "https://recom.example/problems/auth/invalid-continuation-token",
      "title": "Continuation token rejected",
      "detail": "The continuation token is not valid for this installation."
    },
    {
      "code": "auth.invalid_credentials",
      "status": 401,
      "type": "https://recom.example/problems/auth/invalid-credentials",
      "title": "Authentication failed",
      "detail": "The supplied credentials could not be verified."
    },
    {
      "code": "auth.project_forbidden",
      "status": 403,
      "type": "https://recom.example/problems/auth/project-forbidden",
      "title": "Project not available to this user",
      "detail": "The requested project is not one this user may work in."
    },
    {
      "code": "auth.projects_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/auth/projects-unavailable",
      "title": "Project list temporarily unavailable",
      "detail": "The authorized project list could not be read. Try again shortly."
    },
    {
      "code": "auth.provider_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/auth/provider-unavailable",
      "title": "Authentication temporarily unavailable",
      "detail": "The authentication service could not be reached. Try again shortly."
    },
    {
      "code": "auth.rate_limit_exceeded",
      "status": 429,
      "type": "https://recom.example/problems/auth/rate-limit-exceeded",
      "title": "Too many attempts",
      "detail": "Too many requests. Retry after the indicated delay."
    },
    {
      "code": "auth.unauthorized",
      "status": 401,
      "type": "https://recom.example/problems/auth/unauthorized",
      "title": "Authentication required",
      "detail": "A valid access token is required for this resource."
    },
    {
      "code": "controllers.command_equipment_not_fitted",
      "status": 409,
      "type": "https://recom.example/problems/controllers/command-equipment-not-fitted",
      "title": "Equipment not fitted",
      "detail": "The controller is not fitted with the equipment the command addresses, such as a master valve, a fertilizer valve or a filter."
    },
    {
      "code": "controllers.command_forbidden",
      "status": 403,
      "type": "https://recom.example/problems/controllers/command-forbidden",
      "title": "Command not permitted for this user",
      "detail": "This user's access level in the project does not include the capability the command requires."
    },
    {
      "code": "controllers.command_layout_unsupported",
      "status": 409,
      "type": "https://recom.example/problems/controllers/command-layout-unsupported",
      "title": "Command not supported by this firmware layout",
      "detail": "The controller's firmware layout does not carry the address this command writes."
    },
    {
      "code": "controllers.command_model_unsupported",
      "status": 409,
      "type": "https://recom.example/problems/controllers/command-model-unsupported",
      "title": "Command not supported by this controller model",
      "detail": "The controller's model accepts no commands, or not this one."
    },
    {
      "code": "controllers.command_not_sendable",
      "status": 409,
      "type": "https://recom.example/problems/controllers/command-not-sendable",
      "title": "Command declared but not sendable",
      "detail": "This command is declared for the model but its device behaviour is not confirmed, so it is not sent."
    },
    {
      "code": "controllers.command_partially_accepted",
      "status": 502,
      "type": "https://recom.example/problems/controllers/command-partially-accepted",
      "title": "Command only partially accepted",
      "detail": "The delivery service accepted some of the command's writes and refused the rest. Read the controller's state before retrying."
    },
    {
      "code": "controllers.command_state_unknown",
      "status": 409,
      "type": "https://recom.example/problems/controllers/command-state-unknown",
      "title": "Controller state unavailable",
      "detail": "The controller has no usable state report for this command. Retry once the controller reports."
    },
    {
      "code": "controllers.command_target_out_of_range",
      "status": 422,
      "type": "https://recom.example/problems/controllers/command-target-out-of-range",
      "title": "Valve or program number out of range",
      "detail": "The valve or program number is outside what this controller has configured."
    },
    {
      "code": "controllers.command_transport_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/controllers/command-transport-unavailable",
      "title": "Command delivery service unavailable",
      "detail": "The service that delivers writes to controllers could not be reached, did not answer in time, or accepted nothing. As far as this API knows nothing was sent; read the controller's state before retrying."
    },
    {
      "code": "controllers.command_value_out_of_range",
      "status": 422,
      "type": "https://recom.example/problems/controllers/command-value-out-of-range",
      "title": "Value out of range for the device",
      "detail": "The value falls outside what the device register can hold."
    },
    {
      "code": "controllers.controller_forbidden",
      "status": 403,
      "type": "https://recom.example/problems/controllers/controller-forbidden",
      "title": "Controller not available to this user",
      "detail": "The requested controller is not one this user may read."
    },
    {
      "code": "controllers.controller_not_found",
      "status": 404,
      "type": "https://recom.example/problems/controllers/controller-not-found",
      "title": "Controller not found",
      "detail": "No controller with the requested id exists."
    },
    {
      "code": "controllers.data_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/controllers/data-unavailable",
      "title": "Controller data temporarily unavailable",
      "detail": "Controller data could not be read. Try again shortly."
    },
    {
      "code": "controllers.project_forbidden",
      "status": 403,
      "type": "https://recom.example/problems/controllers/project-forbidden",
      "title": "Project not available to this user",
      "detail": "The requested project is not one this user may work in."
    },
    {
      "code": "controllers.realtime_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/controllers/realtime-unavailable",
      "title": "Controller real-time state temporarily unavailable",
      "detail": "The real-time state store could not be read. Retry shortly or request the history source."
    },
    {
      "code": "http.method_not_allowed",
      "status": 405,
      "type": "https://recom.example/problems/http/method-not-allowed",
      "title": "Method not allowed",
      "detail": "The HTTP method is not supported for this resource."
    },
    {
      "code": "http.not_found",
      "status": 404,
      "type": "https://recom.example/problems/http/not-found",
      "title": "Resource not found",
      "detail": "The requested resource does not exist."
    },
    {
      "code": "http.unsupported_media_type",
      "status": 415,
      "type": "https://recom.example/problems/http/unsupported-media-type",
      "title": "Unsupported media type",
      "detail": "The request content type is not supported."
    },
    {
      "code": "logs.file_not_found",
      "status": 404,
      "type": "https://recom.example/problems/logs/file-not-found",
      "title": "Log file not found",
      "detail": "The requested log file does not exist."
    },
    {
      "code": "push.controller_access_denied",
      "status": 403,
      "type": "https://recom.example/problems/push/controller-access-denied",
      "title": "Controller access denied",
      "detail": "One or more selected controllers cannot be used for notifications."
    },
    {
      "code": "push.event_not_allowed",
      "status": 400,
      "type": "https://recom.example/problems/push/event-not-allowed",
      "title": "Push event is not allowed",
      "detail": "One or more selected events are not available for notifications."
    },
    {
      "code": "push.invalid_registration",
      "status": 400,
      "type": "https://recom.example/problems/push/invalid-registration",
      "title": "Invalid push registration",
      "detail": "The Firebase app or installation registration is not supported."
    },
    {
      "code": "push.invalid_subscription",
      "status": 400,
      "type": "https://recom.example/problems/push/invalid-subscription",
      "title": "Invalid push subscription",
      "detail": "The subscription mode or selected filters are not supported."
    },
    {
      "code": "push.no_authorized_controllers",
      "status": 400,
      "type": "https://recom.example/problems/push/no-authorized-controllers",
      "title": "No authorized controllers",
      "detail": "The caller is not authorized for any controller, so an authorized-scope subscription would never match an event."
    },
    {
      "code": "push.persistence_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/push/persistence-unavailable",
      "title": "Push subscriptions temporarily unavailable",
      "detail": "Push subscriptions could not be read or updated. Try again shortly."
    },
    {
      "code": "push.subscription_not_found",
      "status": 404,
      "type": "https://recom.example/problems/push/subscription-not-found",
      "title": "Push subscription not found",
      "detail": "The requested push subscription was not found."
    },
    {
      "code": "push.test_send_disabled",
      "status": 403,
      "type": "https://recom.example/problems/push/test-send-disabled",
      "title": "Push diagnostic sending is disabled",
      "detail": "Diagnostic notification sending is not enabled for this environment."
    },
    {
      "code": "request.body_too_large",
      "status": 413,
      "type": "https://recom.example/problems/request/body-too-large",
      "title": "Request body too large",
      "detail": "The request body exceeds the permitted size."
    },
    {
      "code": "request.malformed",
      "status": 400,
      "type": "https://recom.example/problems/request/malformed",
      "title": "Request could not be read",
      "detail": "The request body or parameters could not be parsed."
    },
    {
      "code": "request.validation_failed",
      "status": 400,
      "type": "https://recom.example/problems/request/validation-failed",
      "title": "Request validation failed",
      "detail": "One or more request fields are invalid."
    },
    {
      "code": "server.unexpected",
      "status": 500,
      "type": "https://recom.example/problems/server/unexpected",
      "title": "Unexpected error",
      "detail": "An unexpected error occurred. The failure was recorded."
    },
    {
      "code": "service_calls.controller_forbidden",
      "status": 403,
      "type": "https://recom.example/problems/service-calls/controller-forbidden",
      "title": "Controller not available to this user",
      "detail": "A service call can only be opened on a controller this user is authorized to work in."
    },
    {
      "code": "service_calls.data_unavailable",
      "status": 503,
      "type": "https://recom.example/problems/service-calls/data-unavailable",
      "title": "Service call data temporarily unavailable",
      "detail": "Service call data could not be read or written. Try again shortly."
    },
    {
      "code": "service_calls.project_forbidden",
      "status": 403,
      "type": "https://recom.example/problems/service-calls/project-forbidden",
      "title": "Project not available to this user",
      "detail": "The requested project is not one this user may work in."
    },
    {
      "code": "service_calls.service_call_not_found",
      "status": 404,
      "type": "https://recom.example/problems/service-calls/service-call-not-found",
      "title": "Service call not found",
      "detail": "No service call with the requested id is available to this user."
    },
    {
      "code": "service_calls.unknown_code",
      "status": 400,
      "type": "https://recom.example/problems/service-calls/unknown-code",
      "title": "Value outside the service call vocabulary",
      "detail": "One of the submitted codes is not part of the stored service call vocabulary. Read GET /api/v1/service-calls/vocabulary for the accepted values."
    }
  ]
}