# The uCentral communication protocol
In order to operate in a uCentral system, devices and services must operate using a specific protocol. This protocol describes 
the interaction between the managed devices and the controller that manages the devices. This communictaion protocol
uses the [WebSocket protocol](https://tools.ietf.org/html/rfc6455) on port 15002.

## The controller
The controller is an application waiting for connection from devices on a given port. The controller waits for connections
over TCP. The controller can operate over IPv4 in this initial version. An IPv6 version will exist later. The controller
is able to support thousands of devices.

## The devices
A device will be given a way to find the IP address of its controller as well s the port to communicate over. Devices always initiate 
the connection to the controller.


## The connection
The connection uses the WebSocket protocol to maintain and frame messages. The communication protocol used is modeled after JSON-RPC for sending JSON structured messages.

## The messages
The controller can send commands to the devices. These commands must be acknowledged by the devices. Any errors should be reported byu the devices. The devices may send unsolicited 
messages to the devices. These messages are not acknowledged by the controller and should be expected to be received and processed. The next section explains the different messages.  

### Event Messages
In this RPC, here are some common interpretations:
- `when` : In a command, this is a suggestion as to when to perform something. 0 means right now, or otherwise the UTC time in seconds.
- `serial` : This is the text representation of the serial number the device is using. Usually will be the MAC address of the device without an separator.
- `uuid` : Is an int64 representing the current configuration ID.
- `JSON documents` : when a field requires an JSON document, this is free form JSON and the controller and the AP agree on its content.
-
#### Connection event
Device Sends connection notification to the controller after establishing a connection. The controller
my decide to send the AP a newer configuration. The controller will record the device capabilities provided.
```json
{     "jsonrpc" : "2.0" , 
      "method" : "connect" , 
      "params" : {
        "serial" : <serial number> ,
        "uuid" : <current active configuration uuid>,
        "firmware" : <Current firmware version string>,
        "wanip" : [ IP:Port, ... ], (a list of IPs the device is using as WAN IP and port as strings. IPv4 and IPv6, including the port)
                                    (example: [ "24.17.1.23:54322" , "[2345:23::234]:32323" ] )
        "capabilities" : <JSON Document: current device capabilities.>
    }
}
```

#### State event
The device sends device state information periodically. If the controller detects that it has a newer configuration, it
may decide to send this new configuration to the AP.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "state" , 
    "params" : {
        "serial" : <serial number> ,
        "uuid" : <current active configuration uuid>,
	    "request_uuid" : <optional string identifying the request that triggered this state event. The absence(or empty) means that this is a normal scheduled state>
        "state" : <JSON Document: current device state.>
      }
}
```

#### Healthcheck event
Device sends a `healthcheck` periodically. This message contains information about how vital subsystems are operating and 
if they need attention.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "healthcheck" , 
    "params" : {
        "serial" : <serial number> ,
        "uuid" : <current active configuration uuid>,
	    "request_uuid" : <optional string identifying the request that triggered this healthcheck. The absence(or empty) means that this is a normal scheduled healthcheck>
        "sanity: <integer representing a percentage level of operation. 0 - device is dead 100 - all perfect.>
        "data" : <Optiona/may be empty: JSON Document about current device healthcheck.>
      }
}
```

#### Log event
Device sends a log message whenever necessary. The controller will log this message to the log system for the device.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "log" , 
    "params" : {
        "serial" : <serial number> ,
        "log" : <text to appear in the logs>
        "severity" : <as stated below>,
        "data" : <Optiona/may be empty: JSON Document providing additional information related to this log message>
    }
}
```

#### Events Channel
Device sends unsolicited events to the controller.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "event" , 
    "params" : {
        "serial" : "001122334455" ,
        "data" : { 
          "event" : [
            1871263817263,
            {
              "type" : "the event type",
              "payload" : {
                "field1" : "value1"
              }
            }
          ]
        }
    }
}
```

The first element of the `event` array is always the `timestamp` of the event. The `payload` is a JSON document contains addition information about the event. This _may not_ be empty.

#### Alarms Channel
Device sends unsolicited alarms to the controller.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "alarm" , 
    "params" : {
        "serial" : <serial number> ,
        "data" : <Optiona/may be empty: JSON Document providing additional information related to this event message>
    }
}
```

#### Wifiscan Channel
Device sends unsolicited wifiscans to the controller.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "wifiscan" , 
    "params" : {
        "serial" : <serial number> ,
        "data" : <Optiona/may be empty: JSON Document providing additional information related to this wifiscan message>
    }
}
```

##### `severity`
The `severity` matches the `syslog` levels. Here are the details:
- 0 : LOG_EMERG       0       /* system is unusable */
- 1 : LOG_ALERT       1       /* action must be taken immediately */
- 2 : LOG_CRIT        2       /* critical conditions */
- 3 : LOG_ERR         3       /* error conditions */
- 4 : LOG_WARNING     4       /* warning conditions */
- 5 : LOG_NOTICE      5       /* normal but significant condition */
- 6 : LOG_INFO        6       /* informational */
- 7 : LOG_DEBUG       7       /* debug-level messages */

#### Crash Log event
Device may send a `crash log event` during rebooting after a crash. The event cannot be sent until a connection event has been established.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "crashlog" , 
    "params" : {
        "serial"    : <serial number> ,
        "uuid"      : <the UUID of the configuration that generated the crash log>,
        "loglines"  : [ an array of strings representing the logs from the log file ]
      }
}
```

#### Reboot Log event
The device may send a `reboot log event` after a reboot. This maybe a scheduled reboot or caused in some other way.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "rebootLog" , 
    "params" : {
        "serial"  : <serial number> ,
        "uuid"    : <the UUID of the configuration that generated the reboot log>,
        "date"    : <Unix time when this reboot occurred>,
        "type"    : <string>,
        "info"    : [ "info 1", "info 2"]
      }
}
```

Here is a possible list of reboot reasons:

#### Config change pending event
Device sends this message to tell the controller that the device 
has received a configuration but is still running an older configuration. The controller will not
reply to this message.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "cfgpending" , 
    "params" : {
        "serial" : <serial number> ,
        "active" : <UUID current active configuration uuid>,
        "uuid" : <UUID waiting to apply this configuration>
    }
}
```

#### DeviceUpdate event
Device sends this message to tell the controller it is changing something is its configuration because
of some requirement or some changes.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "deviceupdate" , 
    "params" : {
        "serial" : <serial number>,
        # a list of key value pairs representing the change i.e
        # "currentPassword" : "mynewpassword"
    }
}
```

#### Send a keepalive to the controller event
Device sends a keepalive whenever necessary. The device will send this message to tell the controller
which version it is running. The Controller may decide to send the device a newer configuration.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "ping" , 
    "params" : {
        "serial" : <serial number> ,
        "uuid" : <current running config>
    }
}
```

#### Recovery Event
Device may decide it has to do into recovery mode. This event should be used.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "recovery" , 
    "params" : {
        "serial" : <serial number> ,
        "uuid"   : <the UUID of the configuration that generated the crash log>,
        "firmware: <the string describing the current firmware>,
        "reboot" : true/false    (shoudld the device be instructed to reboot after loggin the information),
        "loglines" : [ an array of strings representing the logs from the log file ]
      }
}
```

The device should answer:
```json
{    "jsonrpc" : "2.0" ,
    "result" : {
        "serial" : <serial number> ,
        "status" : {
          "error" : 0 or an error number,
          "text" : <description of the error or success>
        }
  },
  "id" : <same number>
}
```

#### Device requests a venue broadcast message
Device send this message when it wants to reach out to all other APs in the same venue. The GW will find the 
venue where this device belongs and resend the same message to all other devices in the venue.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "venue_broadcast" , 
    "params" : {
        "serial" : <serial number> ,
        "timestamp" : <the UTC timestamp when the message was sent>,
        "data" : <JSON document to broadcast>
    }
}
```
Upon receiving a `venue_broadcast` message, the GW will simply resent the message to all the APs in the venue.

### Controller commands
Most controller commands include a `when` member. This is a UTC clock time asking the AP
to perform the command at that time. This is a suggestion only. The AP may ignore this
parameter. If a 0 (zero) is given, the command should be performed immediately. `when` is
always a numeric parameter.

#### Controller wants the device to apply a given configuration
Controller sends this command when it believes the device should load a new configuration. The device
should send message with `pending change` events until this version has been applied and running.
```json
{   "jsonrpc" : "2.0" , 
    "method" : "configure" , 
    "params" : {
        "serial" : <serial number> ,
        "uuid" : <waiting to apply this configuration>,
        "when" : Optional - <UTC time when to apply this config, 0 mean immediate, this is a suggestion>
        "config" : <JSON Document: New configuration”
     },
     "id" : <some number>
}
```

The device should answer:
```json
{    "jsonrpc" : "2.0" , 
     "result" : {
         "serial" : <serial number> ,
         "uuid" : <waiting to apply this configuration>,
         "status" : {
             "error" : 0 or an error number,
             "text" : <description of the error or success>
             "when" : <indication as to when this will be performed>,
             "rejected" : [
                            {   "parameter" : <JSON Document: text that caused the rejection> ,
                                "reason" : <why it was rejected>,
                                "substitution" : <JSON Document: replaced by this JSON. Optional> 
                            }
                        ]
             }
         },
     "id" : <same number>
}
```

#### Controller wants the device to apply a given fixed configuration

Controller sends this command when it requires the device to apply fixed configuration, eg. country code. The device
should respond with message indicating failure or success.

```json
{   "jsonrpc" : "2.0",
    "method" : "fixedconfig",
    "params" : {
        "serial" : <serial number>,
        "when" : Optional - <UTC time when to apply this config, 0 means immediate, this is a suggestion>
        "country" : "<country-code>"
     },
}
```

If AP supports compressed configuration feature by inidcating `compress_cmd=true` in its capabilities, controller
will send a compressed configuration message where configuration payload (i.e. contents of `params`) is compressed
and encoded in base64 format:
```json
{   "jsonrpc" : "2.0",
    "method" : "configure",
    "params" : {
        "compress_64" : "<b64 encoded zlib compressed payload>",
        "compress_sz" : "<size of uncompressed data in bytes>"
     },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0",
    "result" : {
        "serial": <serial number>,
        "status": {
            "error": 0 or an error number,
            "text": <description of the error or success, eg. "Applied fixed config, rebooting">
        },
        "uuid": <UUID>
    }
}

```


##### The Answer
The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with
appropriate values. This could be used to allow a device to replace frequencies for the regions it is located in. The device 
can provide an array of these rejections. The substitution JSON is optional.

###### Error codes
- 0 : configuration was applied as-is.
- 1 : configuration was applied with the included substitutions in the `rejected` section. The device is operating with the new modified config.
- 2 : configuration was rejected and will not be applied at all. The `rejected` section can be used to tell the controller why.

###### The `rejected` section
The rejected section is an array containing the following:
- `parameter` : the JSON code in the config that is causing this rejection
- `reason` : anything to explain the rejection.
- `substution` : the JSON code that `parameter` was replaced with. This could be absent meaning that the `parameter` code was simply removed from the configuration.

#### Controller wants the device to reboot
Controller sends this command when it believes the device should reboot.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "reboot" , 
     "params" : {
	        "serial" : <serial number> ,
	        "when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
      "serial" : <serial number> ,
      "status" : {
	    "error" : 0 or an error number,
	    "text" : <description of the error or success>,
	    "when" : <time when this will be performed as UTC seconds>,
  	},
  "id" : <same number>
}
```
###### Error codes
- 0 : is rebooting at `when` seconds.
- 1 : the device is busy but will reboot soon. `text` may indicate why.
- 2 : the device will not reboot. `text` contains information as to why.

#### Controller wants to power-cycle PoE port(s)
Controller sends this command to power-cycle 1 or more PoE ports
```json
{    "jsonrpc" : "2.0" , 
     "method" : "powercycle" , 
     "params" : {
	        "serial" : <serial number> ,
            "ports" : [ { "name" :  "Ethernet1", "cycle" : 5000}, { "name" :  "Ethernet8", "cycle" : 10000 } ],
	        "when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
      "serial" : <serial number> ,
      "status" : {
	    "error" : 0 or an error number,
	    "text" : [ "Error 1" , "Error 2" ],
	    "when" : <time when this will be performed as UTC seconds>,
  	},
  "id" : <same id from request>
}
```

###### Error codes
- 0 : is rebooting at `when` seconds.
- 1 : the device is busy but will reboot soon. `text` may indicate why.
- 2 : the device will not reboot. `text` contains information as to why.

#### Controller wants the device to upgrade its firmware
Controller sends this command when it believes the device should upgrade its firmware.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "upgrade" , 
     "params" : {
	        "serial" : <serial number> ,
	        "when"  : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
		    "uri"   : <URI to download the firmware>,
            "FWsignature" : <string representation of the signature for the FW> (optional)
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
            "when" : <time when this will be performed as UTC seconds>,
          }
  	  },
      "id" : <same number>
}
```
Here are the error values
```text
0:  No error
1:  Bad firmware
2:  Missing signature
```


#### Controller wants the device to perform a factory reset
Controller sends this command when it believes the device should upgrade its firmware.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "factory" , 
     "params" : {
        "serial" : <serial number> ,
        "when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
        "keep_redirector" : <0 or 1>
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
            "when" : <time when this will be performed as UTC seconds>
          }
      },
  "id" : <same number>
}
```

#### Controller issuing RRM commands to the AP 
Controller sends this command to perform several RRM commands.
```json
{    "jsonrpc" : "2.0" ,
     "method" : "rrm" ,
     "params" : {
                "serial" : <serial number> ,
                "actions": [
                        {
                                "type": "roam",
                                "bss": [ "00:11:22:33:44:55", ... ],
                                "params" : { action specific data }
                        }, {
                                "type": "tx-power",
                                "bss": [ "00:11:22:33:44:55", ... ],
                                “params”: { action specific data }
                        }, {
                                "type": "beacon-request",
                                "bss": [ "00:11:22:33:44:55", ... ],
                                "params": { action specific data }
                        }
                ]
        },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
          }
      },
  "id" : <same number>
}
```

#### Controller wants the device to flash its LEDs
Controller sends this command when it wants the device to flash its LEDs.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "leds" , 
     "params" : {
        "serial" : <serial number> ,
        "when" : Optional - <UTC time when to upgrade the firmware, 0 mean immediate, this is a suggestion>,
        "duration" : number in milliseconds (only applies to the "blink" pattern)
        "pattern" : One of "on", "off", or "blink"
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
          }
  	},
  "id" : <same number>
}
```

###### Error codes
- 0 : device will perform blink at `when` seconds.
- 1 : device cannot flash LEDs because it does not have any.
- 2 : device rejects the request. `text` should include information as to why.

#### Controller wants the device to perform a trace
Controller sends this command when it needs the device to perform a trace (i.e. tcpdump).
```json
{    "jsonrpc" : "2.0" , 
     "method" : "trace" , 
     "params" : {
	        "serial" : <serial number> ,
	        "when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>,
	        "duration" : <integer representing the number of seconds to run the trace>
	        "packets" : <integer for the number of packets to capture>
	        "network" : <string identifying the network to trace>
	        "interface" : <string identifying the interface to capture on>
	        "uri" : <complete URI where to upload the trace. This URI will be available for 30 minutes following a trace request start>
        },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0" , 
    "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
            "when" : <time when this will be performed as UTC seconds>
  	        }
        },
    "id" : <same number>
}
```

##### About tracing
###### 'packets' and 'duration'
The device can interpret the parameters `packets` and `duration` anyway it wants. Both are optional. The AP could decide to
interpret this as a maximum of `duration` or until `packets` have been received. Or perform an `and` between the two. This
is left to the implementer.

###### 'uri'
The `uri` for file upload is available for 30 minutes following the start of the capture. Once the file has been
uploaded or the timeout occurs, the upload will be rejected.

#### Controller wants the device to perform a WiFi Scan
Controller sends this command when it needs the device to perform a WiFi Scan.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "wifiscan" , 
     "params" : {
	        "serial" : <serial number> ,
	        "bands" : [ "2","5","5l","5u",6" ], <optional this is a list of bands to scan: on or more bands >
	        "channels" : [ 1,2,3...] , <optional list of discreet channels to scan >
	        "verbose" : <optional boolean: true or false> (by default false),
	        "bandwidth" : <optional int: 20,40,80 in MHz>,
	        "active" : 0 or 1 (to select passive or active scan),
	        "ies": <optional: array of unsigned int 8 bits: i.e. [1,4,34,58,91]> 
        },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0" , 
    "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
            "when" : <time when this will be performed as UTC seconds>
  	        },
          "scan" : <JSON document detailing the results of the scan>
        },
    "id" : <same number>
}
```

##### Scanning: bands or channels
In the command, bands and channels are mutually exclusive. If both parameters are omitted, then the scan will be performed for all bands and all channels.

#### Controller requesting a specific message
Controller sends this command when it needs the device to provide a message back ASAP. The currently 
supported messages are "state" and "healthcheck". More messages maybe added later. The messages will
be returned the usual way. The RPC response to this message just says that the request has been accepted and the
message will be returned "soon".
```json
{    "jsonrpc" : "2.0" , 
     "method" : "request" , 
     "params" : {
	        "serial" : <serial number> ,
	        "when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>,
	        "message" : "state" or "healthcheck",
		    "request_uuid" : <optional UUID string. If present during the request, the next message will also contains this field>
        },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0" , 
    "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
            "when" : <time when this will be performed as UTC seconds>
  	        }
        },
    "id" : <same number>
}
```

#### Controller requesting eventqueue buffers
Controller sends this command when it needs the device to provide the content of ist ring buffers.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "event" , 
     "params" : {
	        "serial" : <serial number> ,
	        "when" : Optional - <UTC time when to reboot, 0 mean immediately, this is a suggestion>,
	        "types" : [ "dhcp", "rrm"], <this must be an array: array of 1 or 2 elements, right now only "rrm" and "dhcp" are supported>
    		"request_uuid" : <optional UUID string. If present during the request, the next message will also contains this field>
        },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0" , 
    "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>
  	        },
          "events" : <JSON document describing the events> 
        },
    "id" : <same number>
}
```

#### Controller requesting telemetry stream information
Controller sends this command when it needs the device to telemetry streaming.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "telemetry" , 
     "params" : {
	        "serial" : <serial number> ,
	        "interval" : 0-60, # number of seconds for polling information. 0 means to shutdown the stream 
	        "types" : [ "dhcp", "rrm"], <this must be an array: array of 1 or 2 elements, right now only "rrm" and "dhcp" are supported
        },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0" , 
    "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>
  	        }
        },
    "id" : <same number>
}
```

When the interval is greater than 0, the gateway will start to receive messages
```json
{   "jsonrpc" : "2.0" , 
    "method" : "telemetry" , 
    "params" : {
        "serial" : <serial number> ,
        "data" : <A JSON document describing the information coming from the device>
      }
}
```

The device will stop sending data after 30 minutes or if it receives a `telemetry` command with an interval of 0.


#### Controller requesting an `rtty` session
Controller sends this command an administrator requests to start an `rtty` session with the AP. 
```json
{    "jsonrpc" : "2.0" , 
     "method" : "remote_access" , 
     "params" : {
            "method" : "rtty"
	        "serial" : <serial number> ,
	        "token" : <string representing the rtty server token. Must be sent to the rtty server>,
	        "id" : <string representing the device ID. Mus tbe sent to the rtty server.>,
	        "server": <rtty server FQDN or IP address>,
	        "port" : <integer reflecting the port the rtty server is listening on>,
		    "user" : <username of the requester. The AP should log this into its logs to show who is accessing the AP>,
		    "timeout" : <number of seconds the AP should wait for a connection>
        },
     "id" : <some number>
}
```

The device should answer:
```json
{   "jsonrpc" : "2.0" , 
    "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : 0 or an error number,
            "text" : <description of the error or success>,
            "meta" : <optional JSON document including additional information about the connection.>
  	        }
        },
    "id" : <same number>
}
```

#### Controller wants to ping the device
Controller sends this command when it tries to establish latency to the device.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "ping" , 
     "params" : {
	        "serial" : <serial number>
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
              "serial" : <serial number> ,
              "uuid" : <uuid of the current active configuration>,
              "deviceUTCTime" : <UTC Time on device in milliseconds>
            },
      "id" : <same number>
}
```

#### Controller wants the device to perform a script
Controller sends this command to run a predefined script. Extreme care must be taken.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "script" , 
     "params" : {
        "serial" : <serial number>,
        "type" : <one of "shell", "ucode", "bundle">,
        "script" : <text blob containing the script, This must be vase64 encoded>,
        "timeout" : <max timeout in seconds, default is 30, unused if URI is supplied>,
        "uri":  "<upload script results using this URI>",
        "signature" : "<signature for script>: must be supplied to restricted devices",
        "when" : <time when this will be performed as UTC seconds>
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
	    one of either
	    	"result_64" : <gzipped base64 result of running the command>,
	    	"result_sz" : <size of unzipped content>
	    or 
	    	"result" : <a single text blob of the result>
          }
      },
  "id" : <same number>
}
```

#### Controller wants the device to replace its certificates
Controller sends this command to run a predefined script. Extreme care must be taken.
```json
{    "jsonrpc" : "2.0" , 
     "method" : "certupdate" , 
     "params" : {
        "serial" : <serial number>,
        "certificates" : <BASE64 encoded tar file of the cert package from the certificate portal>
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
            "txt" : <text describing the error or success>
      },
  "id" : <same number as request>
}
```

#### Controller wants the device to switch to another controller
Controller sends this when the device should change the controller it connects to without looking up a new redirector.

```json
{    "jsonrpc" : "2.0" , 
     "method" : "transfer" , 
     "params" : {
        "serial" : <serial number>,
        "server" : <controller hostname>,
        "port" : <controller port number (integer)>,
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
            "txt" : <text describing the error or success>
      },
  "id" : <same number as request>
}
```

### RRM AP device commands
The following command is used to send RRM commands to an AP. RRM commands are send to an AP, however the 
controller will not or cannot verify if they have been sent or the action was performed.

```json
{    "jsonrpc" : "2.0" , 
     "method" : "rrm" , 
     "params" : {
        "serial" : <serial number>,
        "actions" : [ array of actions. Each possible action is defined next]
     },
     "id" : <some number>
}
```

The device should answer:
```json
{     "jsonrpc" : "2.0" , 
      "result" : {
          "serial" : <serial number> ,
          "status" : {
            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
            "txt" : <text describing the error or success>
      },
  "id" : <same number as request>
}
```

#### RRM Roam action

##### Kick
```json
{     
      "action" : "kick" ,
      "addr" : <mac if the client that shall be kicked> ,
      "reason": <number>, (default: 5, https://www.cisco.com/assets/sol/sb/WAP371_Emulators/WAP371_Emulator_v1-0-1-5/help/Apx_ReasonCodes2.html)
      "ban_time": <number> (seconds, optional)
}
```

##### Channel Switch Announcement
```json
{   
    "action" : "channel_switch" ,
    "bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
    "channel" : <number> (HT/HW mode will be retained upon issuing the CSA)
}
```

##### Change TX-Power
```json
{   
    "action" : "tx_power" ,
    "bssid" : <mac of the SSID> , (all other SSIDs on the same radio will perform the same action)
    "level" : <number> (DBm inside the positive number space)
}
```

##### Beacon Scan
```json
{   
    "action" : "beacon_request" ,
    "addr" : <mac if the client that shall perform the scan> ,
    "ssid": <string>, (the SSID the client shall scan for on all frequencies),
    "channel": <number> (the channel that shall be scanned)
}
```

##### BSS Transition
```json
{   
    "action" : "bss_transition" ,
    "addr" : <mac if the client that shall perform the roam> ,
    "neighbors": [ <string> ], (an array of BSSIDs the client shall consider as roamin candidates)
}
```

##### Update neighbours
```json
{   
    "action" : "neighbors" ,
    "bssid" : <mac of the SSID> , (the SSID of the specific VAP)
    "neighbors": [ [ <BSS>, <ssid>, <neighbor report> ] ]
}
```

### `rtty server`
More information about the [rtty server](https://github.com/zhaojh329/rtty) can be found here.

### Message compression
Some messages may be several KB in size. If these messages repeat often, they may cause added data charges over time. 
As a result, the device may decide to compress and base64 outgoing messages. 
Only messages over 3K in size should be compressed. This should apply to the `state` event and possibly the `healtcheck` event. 
Should other messages get larger, the client may decide to compress the. Only messages from the device to the controller may use compression.

#### Identifying a compressed message
A compressed message has a single member to the `params` field. It's only parameter must be called `compress_64`. Any other elements under
params will be dropped. Additional compression schemes may be developed later. The device should also include 
a hint to the actual size of the uncompressed data. This would allow listeners to create sufficiently sized 
buffers right away instead of guessing. If the device includes `compressed_sz` as the second field in the 
params objects. This should be an unsigned int representing the total size of the uncompressed data. 

#### How to compress
The original `params` element should be run through `zlib:compress` and then encoded using base64, and passed as a string. Here is an example
of the completed message. The following should how the `state` event could be compressed:

```json
{   "jsonrpc" : "2.0" , 
    "method" : "state" , 
    "params" : {
	    "compress_64" : "kqlwhfoihffhwleihfi3uhfkjehfqlkwhfqkhfiu3hffhkjwehfqkwjehfqwiefkjehq.....qwjqkfhqjwk",
        "compress_sz" : 212322
  }
}
```

### 'Radius Proxying'
The gateway can receive RADIUS messages from the device and forward them. It can also receive messages
on its behalf and send them to the device.

```json
{
    "radius" : <type, can be auth, acct, coa> ,
    "data" : <base 64 encoded raw RADIUS payload>
}
```

The GW will include a TLV to mark the sender MAC. The RADIUS server must use the same TLV to
identify the destination for its messages.

#### Incoming RADIUS messages configuration
The GW must be configured with the following:

```asm
radius.proxy.enable = true
radius.proxy.accounting.port = 1813
radius.proxy.authentication.port = 1812
radius.proxy.coa.port = 3799
```




