This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Module RESTful API

RESTful-API documentation including usage examples

The API allows you to use the function of each module.
The basic components like URL structure, versioning and error handling are generic over all modules.

Guide for rapid implementation

This guide is intended to enable a quick implementation and explain the most important points.

  1. Implement the version check and device selection.
    This point is very important because we don’t want problematic implementations that go crazy after an update!
  2. Implement proper error handling.
  3. After the version check and device selection reset the device to initial state using /reset.
    This is not needed if the application uses only “read” requests.
  4. Start by implementing all the GET requests and proceed with POST requests later.
  5. Some functions like /hard_reset, /watchdog or /limits can reset the entire system.
    We do not recommend to implement them if they are not needed by the application!
  6. Implement the /notification endpoint if it is required by the documentation.

Important notes

Multicast DNS auto detection

The API can be detected using mDNS queries.

The service type are “_https._tcp” and “_https._tcp”.
The configuration may be extended by additional txt records in the future. You can find the latest config under /etc/avahi/services/nexus-rest-*.service

The mDNS config (avahi) looks like this:

<service-group>
  <name replace-wildcards="yes">NOREYA NEXUS IO Module API (%h)</name>
  <service>
    <type>_http._tcp</type>
    <port>80</port>
    <txt-record>vendor=noreyatech</txt-record>
    <txt-record>path=/api/io/</txt-record>
    <txt-record>service=io-module</txt-record>
    <txt-record>machine-id=/nexus-machine-id</txt-record>
    <txt-record>tls-ca=/noreya-nexus/certificates/ca.pem</txt-record>
  </service>
  <service>
    <type>_https._tcp</type>
    <port>443</port>
    <txt-record>vendor=noreyatech</txt-record>
    <txt-record>path=/api/io/</txt-record>
    <txt-record>service=io-module</txt-record>
    <txt-record>machine-id=/nexus-machine-id</txt-record>
    <txt-record>tls-ca=/noreya-nexus/certificates/ca.pem</txt-record>
  </service>
</service-group>

Secure communication via HTTPS

It is recommended to secure and trust the communication via HTTPS.
You can retrieve the certificate of the X.509/PEM certification authority via the path in the TXT entry “tls-ca”.
The TLS certificate is valid for the propagated host name and all other host names or IP addresses configured under : http://noreya-nexus.local/nexuscontrolui/system/settings#tls-cert

You should import this certificate on the client and use it for further communication (“trust on first connection strategy”).

Machine ID check

The mDNS implementation handles devices with the same hostname (noreya-nexus) by appending a number (noreya-nexus.local, noreya-nexus-2.local…).
This is great, but has one big problem: If you have 3 hosts and the second one goes offline, the third one gets the second number (noreya-nexus-2.local).
To avoid problems with this behavior, you need to check the unique machine-id provided by the path (plain/txt) in the TXT entry “machine-id”.
We recommend using static IPs or router-defined hostnames (.lan) to avoid this problem, but implementations must deal with this.

1 - Version check and device selection

Describes the /version, /reset and /descriptor endpoints.

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
Tokens can be generated on the http://noreya-nexus.local/nexuscontrolui/system/settings#access-token page.
The username is always “token” while the password must be token value.
You may also want to use the secure protocol https://.

GET /

The “/” (/1.0,/1.1,…) endpoint shows version information and all connected devices handled by this driver.

The “version": “api”: {…} resource must be checked for compatibility by any client.

The “devices” array contains all usable devices and the “slot_number” number must be used to build the further URL.
e.g: “slot_number” is 3:

<HOSTNAME>/api/<service>/<version>/3/descriptor

For the versioning strategy and format, see the Versioning chapter.

The fields “driver_session” and “device_session” must stored by the client and checked frequently.
If any of the values change the client must re-initialize the device.

Request:

Method: GET
URL : localhost/api/<service>/<version>/

Response:

{
  "driver_session": "<String>",
  "version": {
    "api": {
      "major": <uint>,
      "minor": <uint>,
      "patch": <uint>
    },
    "service": {
      "major": <uint>,
      "minor": <uint>,
      "patch": <uint>
    },
    "module_driver": {
      "major": <uint>,
      "minor": <uint>,
      "patch": <uint>
    },
    "kernel_driver": {
      "major": <uint>,
      "minor": <uint>,
      "patch": <uint>
    }
  },
  "devices": [
    {
      "slot_number": <uint>,
      "sdbp_version": {
        "major": <uint>,
        "minor": <uint>,
        "patch": <uint>
      },
      "device_session": "<String>"
    }
  ]
}

Example:

Request:

curl http://localhost/api/bmc/1.0/

Response:

{
  "driver_session": "ZVHGTLCFDUD1FKLJCHG5PWYULHVRJ8AV7Q8A2W703UHVYZFYJPWUCYNDSR65AWUU",
  "version": {
    "api": {
      "major": 0,
      "minor": 9,
      "patch": 0
    },
    "service": {
      "major": 0,
      "minor": 9,
      "patch": 0
    },
    "module_driver": {
      "major": 0,
      "minor": 9,
      "patch": 0
    },
    "kernel_driver": {
      "major": 1,
      "minor": 1,
      "patch": 0
    }
  },
  "devices": [
    {
      "slot_number": 0,
      "sdbp_version": {
        "major": 1,
        "minor": 0,
        "patch": 0
      },
      "device_session": "AAHGTLCFDUD1FKLJCHG5PWYULHVRJ8AV7Q8A2W703UHVYZFYJPWUCYNDSR65AWSS"
    }
  ]
}

POST /reset

Resets the entire module to the initial state.
This is equal to a driver restart (SUSPEND) not a system reset (SYSTEM_RESET).

Request:

Method: POST
URL: localhost/api/<service>/<version>/<slot>/reset

Parameters:

{
  "reset": "yes"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/reset --header "Content-Type: application/json" --request POST --data '{"reset": "yes"}'

Response:

{
  "status": "success"
}

GET /descriptor

The “/descriptor” endpoint shows the device descriptor.

Request:

Method: GET
URL : localhost/api/<service>/<version>/<slot>/descriptor

Response:

{
  "slot_number": <uint>,
  "vendor_product_id": <string>,
  "product_name": <string>,
  "vendor_name": <string>,
  "serial_code": <string>,
  "fw_version": {
    "stability": <string>,
    "version": {
      "major": <uint>,
      "minor": <uint>,
      "patch": <uint>
    }
  },
  "hw_version": {
    "major": <uint>,
    "minor": <uint>,
    "patch": <uint>
  },
  "protocol_version": {
    "major": <uint>,
    "minor": <uint>,
    "patch": <uint>
  },
  "bootloader_state": <string>,
  "max_frame_size": <uint>,
  "max_power_12v": <uint>,
  "max_power_5v0": <uint>,
  "max_power_3v3": <uint>,
  "max_sclk_speed": <uint>
}

Example:

Request:

curl http://localhost/api/bmc/1.0/0/descriptor

Response:

{
  "slot_number": 0,
  "vendor_product_id": "modules.noreya.tech/bmc",
  "product_name": "Baseboard Management Controller",
  "vendor_name": "NOREYA",
  "serial_code": "0000-0000-2039-3639-424E-5317-003A-0036",
  "fw_version": {
    "stability": "A",
    "version": {
      "major": 0,
      "minor": 9,
      "patch": 3
    }
  },
  "hw_version": {
    "major": 4,
    "minor": 1,
    "patch": 1
  },
  "protocol_version": {
    "major": 1,
    "minor": 0,
    "patch": 0
  },
  "bootloader_state": "supported",
  "max_frame_size": 64,
  "max_power_12v": 0,
  "max_power_5v0": 550,
  "max_power_3v3": 7915,
  "max_sclk_speed": 16000
}

2 - Error response handling

Describes how errors should be handled.

On error the HTTP status code is set in the response.
At least the following status codes should be handled: 400, 404, 422, 500, 502 .

All endpoints use a generic response format.

status is always “error”
code is an integer value equal to the http status code
message is a string with a meaningful error message

Response:

{
 "status": "error",
 "code": <http error code(integer)>,
 "message": <String>
}

Example (Not Found)

Request:

curl http://localhost/api/bmc/1.0/0/error_msg

Response:

{
 "status": "error",
 "code": 404,
 "message": "Not Found"
}

Example (Unprocessable Entity)

Request:

curl http://localhost/api/bmc/1.0/0/buzzer --header "Content-Type: application/json" --request POST --data '{"mode": 4, "duration": 0}'

Response:

{
 "status": "error",
 "code": 422,
 "message": "duration out of range"
}

3 - IO Module

IO Module RESTful API documentation

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
You may also want to use the secure protocol https://.

Introduction

The IO Module provides six IOs configureable via RESTful API.
From the implementation perspective the following order should be used:

  1. Implement version check and device selection
  2. Implement GET /input/values for testing
  3. Implement notification error handling and polling
  4. Implement power management
  5. Implement outputs
  6. Test if power management, outputs and notifications (e.g: shortcut a pin) is working
  7. Implement all remaining endpoints

Base URL:

<HOSTNAME>/api/io/<version>/

Version check and device selection

See Version check and device selection

Error response

See Error Response

Caching

By default, all values in the /input directory are cached for 1 second to improve performance during parallel access. To override this cache mechanism, simply add the header cache-control: no-cache to your request.

Notification

GET /notification

Returns pending notifications.
Notifications are messages initiated and send by the module on configured events or (external) errors.
They are handled fast and are usually available >20ms after the event occurred (from the RESTful API point of view).

Request:

Method: GET
URL: <HOSTNAME>/api/io/<version>/<slot>/notification/<pin>

Parameters:

No body parameters

Response:

{
  "under_voltage_alert": <bool>,
  "high_voltage_alert": <bool>,
  "high_current_alert": <bool>,
  "custom_voltage_alert": <bool>
}

Example

Request:

curl http://localhost/api/io/1.0/3/notification/1

Response:

{
  "under_voltage_alert": false,
  "high_voltage_alert": false,
  "high_current_alert": false,
  "custom_voltage_alert": true
}

Power Management

POST /power-management

Too handle different power supply capacities the NOREYA NEXUS platform uses a passive power management concept.
This means that each module must specify its maximum power consumption and the total sum of the maximum power must not exceed the power supply capacity.
The power management daemon can be configured to handle this limit “strict” (do not allow overprovisioning) or “weak” (allow overprovisioning and warn).

The IO Module supports dynamic power configuration which means the application (and therefore the user) must specify how much maximum power per pin is used.
Before the /output/ commands can be used a valid power management configuration must be set.

The position in the array is analog to the pin number.

Please check the current limit for the 5V/12V rail from the datasheet/webpage!

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/power-management

Parameters:

{
    "config": [
        {
            "rail": "5_volt|12_volt",
            "current_milliampere": <int>
        },
        {
            "rail": "5_volt|12_volt",
            "current_milliampere": <int>
        },
        {
            "rail": "5_volt|12_volt",
            "current_milliampere": <int>
        },
        {
            "rail": "5_volt|12_volt",
            "current_milliampere": <int>
        },
        {
            "rail": "5_volt|12_volt",
            "current_milliampere": <int>
        },
        {
            "rail": "5_volt|12_volt",
            "current_milliampere": <int>
        }
    ]
}

Response:

{
  "status": "success|denied",
  "too_much_power": {
    "rail_3v3_milliwatt": <int>,
    "rail_5v0_milliwatt": <int>,
    "rail_12v_milliwatt": <int>
  }
}

Example

Request:

curl http://localhost/api/io/1.0/3/power-management --header "Content-Type: application/json" --request POST --data '{"config": [{"rail": "5_volt", "current_milliampere": 1}, {"rail": "5_volt", "current_milliampere": 1}, {"rail": "5_volt", "current_milliampere": 1}, {"rail": "5_volt", "current_milliampere": 1}, {"rail": "5_volt", "current_milliampere": 1}, {"rail": "5_volt", "current_milliampere": 1}]}'

Response:

{
  "status": "success",
  "too_much_power": {
    "rail_3v3_milliwatt": 0,
    "rail_5v0_milliwatt": 0,
    "rail_12v_milliwatt": 0
  }
}

Input

GET /input/values

Returns the value and type for each pin.

If the pin is configured as analog input, output or pwm the type is “voltage_millivolt” and the value is returned in millivolt.
In output mode the value represents the current voltage level at the pin. The value is load and frequency dependent.

As digital input the type is “digital_input” and the value represents the current logical state 0 (LOW) or 1 (HIGH).

As frequency counter the type is “frequency_hertz” and the value represents the current frequency in Hertz.
Please consider the minimum and maximum frequency value from the datasheet/webpage!

Request:

Method: GET
URL: <HOSTNAME>/api/io/<version>/<slot>/input/values

Parameters:

No body parameters

Response:

{
  "pins": [
    {
      "pin": 1,
      "pin_type": "voltage_millivolt | digital_input | frequency_hertz",
      "value": <int>
    },
    {
      "pin": 2,
      "pin_type": "voltage_millivolt | digital_input | frequency_hertz",
      "value": <int>
    },
    {
      "pin": 3,
      "pin_type": "voltage_millivolt | digital_input | frequency_hertz",
      "value": <int>
    },
    {
      "pin": 4,
      "pin_type": "voltage_millivolt | digital_input | frequency_hertz",
      "value": <int>
    },
    {
      "pin": 5,
      "pin_type": "voltage_millivolt | digital_input | frequency_hertz",
      "value": <int>
    },
    {
      "pin": 6,
      "pin_type": "voltage_millivolt | digital_input | frequency_hertz",
      "value": <int>
    }
  ]
}

Example

Request:

curl http://localhost/api/io/1.0/3/input/values

Response:

{
  "pins": [
    {
      "pin": 1,
      "pin_type": "voltage_millivolt",
      "value": 3300
    },
    {
      "pin": 2,
      "pin_type": "digital_input",
      "value": 1
    },
    {
      "pin": 3,
      "pin_type": "voltage_millivolt",
      "value": 0
    },
    {
      "pin": 4,
      "pin_type": "frequency_hertz",
      "value": 2000
    },
    {
      "pin": 5,
      "pin_type": "voltage_millivolt",
      "value": 0
    },
    {
      "pin": 6,
      "pin_type": "voltage_millivolt",
      "value": 0
    }
  ]
}

GET /input/values/current

Returns the current value for each pin.

The electrical current value is in milliampere.
It is returned independent from the configured mode but is usually zero in input modes.

Please note that this value includes the switching transistor loss.
This means the value will be not accurate especially in pwm mode!
The precision can be compensated by a calibration.

Request:

Method: GET
URL: <HOSTNAME>/api/io/<version>/<slot>/input/values/current

Parameters:

No body parameters

Response:

{
  "pins": [
    {
      "pin": 1,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 2,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 3,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 4,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 5,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 6,
      "pin_type": "current_milliampere",
      "value": 0
    }
  ]
}

Example

Request:

curl http://localhost/api/io/1.0/3/input/values/current

Response:

{
  "pins": [
    {
      "pin": 1,
      "pin_type": "current_milliampere",
      "value": 212
    },
    {
      "pin": 2,
      "pin_type": "current_milliampere",
      "value": 42
    },
    {
      "pin": 3,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 4,
      "pin_type": "current_milliampere",
      "value": 0
    },
    {
      "pin": 5,
      "pin_type": "current_milliampere",
      "value": 345
    },
    {
      "pin": 6,
      "pin_type": "current_milliampere",
      "value": 0
    }
  ]
}

POST /input/mode

Changes the input mode of a pin to analog or digital.
After RESET/SUSPEND the pin is always in analog mode.
Setting a pin to analog mode resets the config, including the analog threshold.

Please check /input/values for the values.

The analog mode is implicitly enabled when the pin is in output/pwm mode, /input/values and /input/analog/thresholds are available.

The digital mode can not be combined with analog/output/pwm modes.

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/input/mode

Parameters:

{
  "pin": <int>,
  "mode": "analog|digital"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/io/1.0/3/input/mode --header "Content-Type: application/json" --request POST --data '{"pin": 1, "mode": "analog"}'

Response:

{
  "status": "success"
}

POST /input/analog/threshold

Enables or disables the analog threshold mode.
The pin must be set into analog mode before the threshold can be enabled.

In analog threshold mode each threshold event triggers a notification on the SDBP.
The result must be checked via /notification endpoint.

The threshold_millivolt can be any value between the 50mV and 25000mV.

Please note that in the current implementation only the state “interrupt triggered” is stored, but not how often.

The api does currently not offer a “debounce_time_milliseconds” parameter. We recommend polling /input/values if this necessary.

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/input/analog/threshold

Parameters:

{
  "pin": <int>,
  "threshold_millivolt": <int>,
  "trigger": "disabled|rising|falling"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/io/1.0/3/input/analog/threshold --header "Content-Type: application/json" --request POST --data '{"pin": 1, "threshold_millivolt": 2000, "trigger": "rising"}'

Response:

{
  "status": "success"
}

POST /input/digital/interrupt

Enables or disables the digital interrupt mode.
The pin must be set into digital mode before the interrupt can be enabled.

In digital interrupt mode each interrupt triggers a notification on the SDBP.
The result must be checked via /notification endpoint.

Please note that in the current implementation only the state “interrupt triggered” is stored, but not how often.

The debounce_time_milliseconds is a value between 0 and 1000 milliseconds.
After the first trigger event the firmware waits debounce_time_milliseconds before sending a notification for a new event. All events in this period are ignored.
This setting is used to prevent interrupt notifications spamming the bus.
It is recommended to set the debounce_time_milliseconds to 20ms or higher.

Some things like switches or buttons typically require a ~250ms debounce_time_milliseconds to send one event per switch/press.

Please check the datasheet/webpage of the module for the HIGH/LOW thresholds.
In case you have different requirements we recommend to use the /input/analog/threshold endpoint.

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/input/digital/interrupt

Parameters:

{
  "pin": <int>,
  "debounce_time_milliseconds": <int>,
  "trigger": "disabled|rising|falling|pulse"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/io/1.0/3/input/digital/interrupt --header "Content-Type: application/json" --request POST --data '{"pin": 1, "debounce_time_milliseconds": 100, "trigger": "rising"}'

Response:

{
  "status": "success"
}

POST /input/digital/counter

Enables or disables the digital counter mode.
The pin must be set into digital mode before the counter can be enabled.

Check /input/values for the counter values.

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/input/digital/counter

Parameters:

{
  "pin": <int>,
  "state": "enabled|disabled"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/io/1.0/3/input/digital/counter --header "Content-Type: application/json" --request POST --data '{"pin": 1, "state": "enabled"}'

Response:

{
  "status": "success"
}

Output

POST /output/state

Configures the output state.
The pin is automatically reset and configured as output if the previous mode was different.

A valid power configuration must exist before this command can be used.

Check /input/values for the values.

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/output/state

Parameters:

{
  "pin": <int>,
  "state": "high|low"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/io/1.0/3/output/state --header "Content-Type: application/json" --request POST --data '{"pin": 1, "state": "high"}'

Response:

{
  "status": "success"
}

POST /output/pwm

Configures the output as pwm output.
The pin is automatically reset and configured as output if the previous mode was different.

A valid power configuration must exist before this command can be used.

Check /input/values for the values.

The pwm function is based on a 16-bit timer with a base frequency of 48MHz.

To configure the PWM the following parameters are important:
prescaler: Divisor for the 48MHz clock.
period: Amount of ticks to reach the target frequency.
time_on: Amount of ticks the signal stays high. Must be < period. e.g: if period = 100 and time_on = 60 the duty cycle is 60%

To simplify the complicated step of PWM calculation we provide a pre-calculated list.

Request:

Method: POST
URL: <HOSTNAME>/api/io/<version>/<slot>/output/pwm

Parameters:

{
  "pin": <int>,
  "prescaler": <int>,
  "time_on": <int>,
  "period": <int>
}

Response:

{
  "status": "success"
}

Example

Request:

# 25.6kHz
curl http://localhost/api/io/1.0/3/output/pwm --header "Content-Type: application/json" --request POST --data '{"pin": 1, "prescaler": 2, "time_on": 312, "period": 625}'

Response:

{
  "status": "success"
}

3.1 - IO Module examples

Basic usage examples

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
You may also want to use the secure protocol https://.

Please ensure nothing is connected to the hardware before running this examples!

Python examples

Get input values for all connected modules

Example:

import requests   

# For tokens see http://noreya-nexus.local/nexuscontrolui/system/settings#access-token
login=("token", "")
hostname="localhost"

resp = requests.get("http://" + hostname + "/api/io/1.0/", auth=login)
if resp.status_code == requests.codes.ok:
  response = resp.json()
  for device in response['devices']:
    print("Input values for module on slot " + str(device['slot_number']) + ":")
    resp = requests.get("http://" + hostname + "/api/io/1.0/" + str(device['slot_number']) + "/input/values", auth=login)
    if resp.status_code == requests.codes.ok:
      response = resp.json()
      for pin in response['pins']:
        print(pin)
    else:
      print("Error response for slot " + str(device['slot_number']))
else:
  print("Error response")

Output:

Input values for module on slot 3 :
{'pin': 1, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 2, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 3, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 4, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 5, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 6, 'pin_type': 'voltage_millivolt', 'value': 0}
Input values for module on slot 4 :
{'pin': 1, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 2, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 3, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 4, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 5, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 6, 'pin_type': 'voltage_millivolt', 'value': 0}
Input values for module on slot 6 :
{'pin': 1, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 2, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 3, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 4, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 5, 'pin_type': 'voltage_millivolt', 'value': 0}
{'pin': 6, 'pin_type': 'voltage_millivolt', 'value': 0}

Configure the power management, turn an output on and check for notifications

Example:

import requests   

# For tokens see http://noreya-nexus.local/nexuscontrolui/system/settings#access-token
login=("token", "")
host_rest_api = "http://localhost/api/io/1.0/"

response = requests.get(host_rest_api, auth=login)
if response.status_code == requests.codes.ok:
    response = response.json()
    for device in response['devices']:
        slot_number = device['slot_number']
        print("Output config for module on slot " + str(slot_number) + ":")

        response = requests.get(host_rest_api + str(slot_number) + "/reset", auth=login)
        if response.status_code == requests.codes.ok:
            print("Successfully reset device")  # We do "write" requests so we need to get a defined state

        request = {"config": [  # Power config is always configured for all pins!
            {"rail": "5_volt", "current_milliampere": 10},
            {"rail": "5_volt", "current_milliampere": 11},
            {"rail": "5_volt", "current_milliampere": 12},
            {"rail": "5_volt", "current_milliampere": 13},
            {"rail": "5_volt", "current_milliampere": 14},
            {"rail": "5_volt", "current_milliampere": 15}
        ]
        }
        response = requests.post(host_rest_api + str(slot_number) + "/power-management", json=request, auth=login)
        if response.status_code == requests.codes.ok:
            print("Power management configured")
            request = {
                "pin": 1,
                "state": "high"
            }
            response = requests.post(host_rest_api + str(slot_number) + "/output/state", json=request, auth=login)
            if response.status_code == requests.codes.ok:
                print("Output 1 is set to HIGH")
            else:
                print("Failed changing output")

            response = requests.get(host_rest_api + str(slot_number) + "/input/values", auth=login)
            if response.status_code == requests.codes.ok:
                response = response.json()
                print("Voltage on output is: " + str(response['pins'][0]['value']) + " mV ")
            else:
                print("Failed getting values")

            response = requests.get(host_rest_api + str(slot_number) + "/notification/1", auth=login)
            if response.status_code == requests.codes.ok:
                response = response.json()
                print("Notification for pin: " + str(response))
            else:
                print("Failed getting notification")

            request = {"reset": "yes"}
            response = requests.post(host_rest_api + str(slot_number) + "/reset", json=request, auth=login)
            if response.status_code == requests.codes.ok:
                print("Successfully reset device after test")
            print("")
        else:
            print("Error response for slot " + str(device['slot_number']))
else:
    print("Error response")

Output:

Output config for module on slot 3:
Power management configured
Output 1 is set to HIGH
Voltage on output is: 4739 mV
Notification for pin: {'under_voltage_alert': False, 'high_voltage_alert': False, 'high_current_alert': False, 'custom_voltage_alert': False}
Successfully reset device after test

Output config for module on slot 4:
Power management configured
Output 1 is set to HIGH
Voltage on output is: 4739 mV
Notification for pin: {'under_voltage_alert': False, 'high_voltage_alert': False, 'high_current_alert': False, 'custom_voltage_alert': False}
Successfully reset device after test

Output config for module on slot 6:
Power management configured
Output 1 is set to HIGH
Voltage on output is: 4750 mV
Notification for pin: {'under_voltage_alert': False, 'high_voltage_alert': False, 'high_current_alert': False, 'custom_voltage_alert': False}
Successfully reset device after test

3.2 - PWM calculation

Configurations and calculation tools

PWM configurations (JSON)

Download optimized PWM settings as JSON structure

Please note that this list does not contain all possible configurations!
You can use the snippet below to search configs in your target frequency range.

Calculation snippet (Python)

def pwm_calc(period_hz):
    BASE_CLK_HZ = 48 * 1000 * 1000
    duty_cycle = 0.5

    #print("Searching for: " + str(period_hz) + "Hz")

    found = False
    for prescaler in range(1, 0xffff, 1):
        tick_time_hz = BASE_CLK_HZ / (prescaler + 1)
        #print("Prescaled base frequency " + str(tick_time_hz) + "Hz")
        if tick_time_hz < period_hz:  # Return if prescaled tickrate is lower than the period
            return (-1, None, None, None)

        if tick_time_hz % 2 == 0:  # Ignore uneven numbers
            for t_period_cnt in range(1, 0xffff, 1):
                t_period = (1 / (t_period_cnt / tick_time_hz))

                if t_period == period_hz:
                    t_on = t_period_cnt * duty_cycle
                    print('Found ' + 'prescaler:' + str(prescaler) + ' t_period:' + str(t_period_cnt) + ' t_on: ' + str(
                        t_on)
                          + ' for frequency (Hz) ' + str(t_period))
                    return period_hz, prescaler, t_period_cnt, t_on

# Select start and stop frequency in Hz. You can also specify the test step.
for i in range(1000,100000,100):
   pwm_calc(i)

4 - Mainboard (BMC)

Mainboard RESTful API documentation

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
You may also want to use the secure protocol https://.

Generic

Base URL:

<HOSTNAME>/api/bmc/<version>/

Version check and device selection

See Version check and device selection

Error response

See Error Response

Voltage

GET /voltage

Returns the voltage in millivolt.

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/voltage

Parameters:

No body parameters

Response:

{
  "voltage_1v8": <mV>,
  "voltage_rtc": <mV>
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/voltage

Response:

{
  "voltage_1v8": 1788,
  "voltage_rtc": 2949
}

Temperature

GET /temperature

Returns the temperature in Celsius. The “ntc_0” shows the temperature emitted by the SoC while the “ntc_1” shows the ambient temperature. The unit is degree Celsius.

Location on the board:

ntc_0: close to the SoC/CPU

ntc_1: close to the buzzer/version information (temp. typically lower)

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/temperature

Parameters:

No body parameters

Response:

{
  "ntc_0": <Temp. in Celsius (float)>,
  "ntc_1": <Temp. in Celsius (float)>
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/temperature

Response:

{
  "ntc_0": 38.703,
  "ntc_1": 29.587
}

Buzzer

POST /buzzer

Controls the integrated buzzer.

“mode” can be:
0 = Internal sounds are disabled
1 = Internal sounds are enabled
2 = Sound 1 played for duration
3 = Sound 2 played for duration
4 = Sound 3 played for duration
5 = Sound 4 played for duration

“duration” must be >= 1 and <= 1000 (milliseconds)

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/buzzer

Parameters:

{
  "mode": <int>,
  "duration": <ms>
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/buzzer --header "Content-Type: application/json" --request POST --data '{"mode": 4, "duration": 100}'

Response:

{
  "status": "success"
}

Watchdog

Controls the internal watchdog function which hard resets the device if the timeout expires.

GET /watchdog

Returns the timeout values in milliseconds.

timeout: current timeout setting

timeout_left: time left until reset

shutdown_timeout: time after the device is reset if a shutdown was initialized

emergency_mode: shows if the device is in emergency mode (storage corrupted, no r/w)

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/watchdog

Parameters:

No body parameters

Response:

{
  "timeout": <ms>,
  "timeout_left": <ms>,
  "shutdown_timeout": <ms>,
  "emergency_mode": <bool>
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/watchdog

Response:

{
  "timeout": 0,
  "timeout_left": 0,
  "shutdown_timeout": 600000,
  "emergency_mode": false
}

POST /watchdog

Enables the watchdog timeout. The timeout is disabled after reset if the config is not saved.

timeout: timeout setting in milliseconds Value must be >= 1000 and <= 600000, 0 means disabled

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/watchdog

Parameters:

{
  "timeout": <ms>,
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/watchdog --header "Content-Type: application/json" --request POST --data '{"timeout": 0}'

Response:

{
  "status": "success"
}

POST /watchdog/sw_shutdown_timeout

Changes the shutdown timeout. The timeout is always stored persistent.

timeout: timeout setting in milliseconds Value must be >= 10000 and <= 600000

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/watchdog/sw_shutdown_timeout

Parameters:

{
  "timeout": <ms>,
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/watchdog/sw_shutdown_timeout --header "Content-Type: application/json" --request POST --data '{"timeout": 100000}'

Response:

{
  "status": "success"
}

POST /watchdog/shutdown

Starts the shutdown watchdog counter. This is the same procedure as triggered by the hardware switch.

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/watchdog/shutdown

Parameters:

{
  "shutdown": "start",
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/watchdog/shutdown --header "Content-Type: application/json" --request POST --data '{"shutdown": "start"}'

Response:

{
  "status": "success"
}

GET /watchdog/alive

Resets the watchdog counter.

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/watchdog/alive

Parameters:

No body parameters

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/watchdog/alive

Response:

{
  "status": "success"
}

GET /watchdog/save

Saves the current timeout configuration persistent.

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/watchdog/save

Parameters:

No body parameters

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/watchdog/save

Response:

{
  "status": "success"
}

USB Hub

Controls the USB hub states.

GET /usbhub

Returns the states of all slots/ports and the hub itself.

state can be “enabled”, “disabled” or “not available”.

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/usbhub

Parameters:

No body parameters

Response:

{
  "hub_state": <state>,
  "port_slot_0": <state>,
  "port_slot_1": <state>,
  "port_slot_2": <state>,
  "port_slot_3": <state>,
  "port_slot_4": <state>,
  "port_slot_5": <state>,
  "port_slot_6": <state>,
  "port_slot_7": <state>,
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/usbhub

Response:

{
  "hub_state": "enabled",
  "port_slot_0": "not available",
  "port_slot_1": "not available",
  "port_slot_2": "enabled",
  "port_slot_3": "enabled",
  "port_slot_4": "enabled",
  "port_slot_5": "enabled",
  "port_slot_6": "enabled",
  "port_slot_7": "disabled",
}

GET /usbhub/devices

Returns all devices connected to the usb hub.
It maps the physical usb port number to the slot number.

Request:

Method: GET
URL: <HOSTNAME>/api/bmc/<version>/<slot>/usbhub/devices

Parameters:

No body parameters

Response:

{
  "devices": [
    {
      "slot": <int>,
      "usb_port": <int>,
      "manufacturer": <string>,
      "product": <string>,
      "serial_code": <string>,
      "system_path": <string/path>
    }
  ]
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/usbhub/devices

Response:

{
  "devices": [
    {
      "slot": 2,
      "usb_port": 3,
      "manufacturer": "NOREYA",
      "product": "ETHERNET V1.1.0",
      "serial_code": "099990002",
      "system_path": "/sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.3"
    }
  ]
}

POST /usbhub

Enables or disables the USB Hub. The /reset command must be used to apply the settings.
The state is boolean and can be true or false.

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/usbhub

Parameters:

{
  "state": boolean,
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/usbhub --header "Content-Type: application/json" --request POST --data '{"state": true}'

Response:

{
  "status": "success"
}

POST /usbhub/slot/

Enables or disables the usb port on the slot.
The /usbhub/reset command must be used to apply the settings.
The state is boolean and can be true or false.

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/usbhub/slot/<number>

Parameters:

{
  "state": <boolean>,
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/usbhub/slot/7 --header "Content-Type: application/json" --request POST --data '{"state": true}'

Response:

{
  "status": "success"
}

POST /usbhub/reset

Resets the USB Hub and applies the saved setting.
CAUTION: On reset all USB devices are disconnected and may drop their connection!

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/usbhub/reset

Parameters:

{
  "reset": "yes",
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/usbhub/reset --header "Content-Type: application/json" --request POST --data '{"reset": "yes"}'

Response:

{
  "status": "success"
}

USB Bootloader

POST /usb_bootloader

Enables the USB Bootloader which allows to access the internal storage (SDCARD/EMMC) via the USB port.
The mode is activated after next reset.
A host device must be connected via USB cable and the USB Bootloader must be activated within 90 seconds otherwise the device will reset to normal mode.

The bootloader tool can be found here.

“enabled” can be true or false ”timeout” must be <= 3600000 milliseconds

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/usb_bootloader

Parameters:

{
  "enabled": <boolean>,
  "timeout": <ms>,
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/usb_bootloader --header "Content-Type: application/json" --request POST --data '{"enabled": false, "timeout": 100000}'

Response:

{
  "status": "success"
}

Hard Reset

POST /hard_reset

Hard resets the device.

Request:

Method: POST
URL: <HOSTNAME>/api/bmc/<version>/<slot>/hard_reset

Parameters:

{
  "reset": "yes"
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/bmc/1.0/0/hard_reset --header "Content-Type: application/json" --request POST --data '{"reset": "yes"}'

Response:

{
  "status": "success"
}

4.1 - BMC examples

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
You may also want to use the secure protocol https://.

Python examples

Get temperature

Example:

import requests

# For tokens see http://noreya-nexus.local/nexuscontrolui/system/settings#access-token
login=("token", "")
hostname="localhost"

resp = requests.get("http://" + hostname + "/api/bmc/1.0/", auth=login)
if resp.status_code == requests.codes.ok:
  response = resp.json()
  for device in response['devices']:
    print("Temperature values for BMC on slot " + str(device['slot_number']) + ":")
    resp = requests.get("http://" + hostname + "/api/bmc/1.0/" + str(device['slot_number']) + "/temperature", auth=login)
    if resp.status_code == requests.codes.ok:
      response = resp.json()
      print("Temperature sensor next to SoC: " + str(response['ntc_0']) + "°C")
      print("Temperature sensor ambient: " + str(response['ntc_1']) + "°C")
    else:
      print("Error response for slot " + str(device['slot_number']))
else:
  print("Error response")

Output:

Temperature values for BMC on slot 0:
Temperature sensor next to SoC: 38.674°C
Temperature sensor ambient: 29.638°C

Watchdog configuration

Example:

import requests
import time

# For tokens see http://noreya-nexus.local/nexuscontrolui/system/settings#access-token
login=("token", "")
hostname="localhost"

response = requests.get("http://" + hostname + "/api/bmc/1.0/", auth=login)
if response.status_code == requests.codes.ok:
  response = response.json()
  for device in response['devices']:
    slot_number = device['slot_number']
    print("Watchdog config for BMC on slot " + str(slot_number) + ":")

    response = requests.get("http://" + hostname + "/api/bmc/1.0/" + str(slot_number) + "/reset", auth=login)
    if response.status_code == requests.codes.ok:
      print("Successfully reset device")  # We do "write" requests so we need to get a defined state

    request = {"timeout": 2000 }
    response = requests.post("http://" + hostname + "/api/bmc/1.0/" + str(slot_number) + "/watchdog", json=request, auth=login)
    if response.status_code == requests.codes.ok:
      print("Watchdog enabled with timeout " + str(request['timeout']) + 'ms')
      response = requests.get("http://" + hostname + "/api/bmc/1.0/" + str(slot_number) + "/watchdog/alive", auth=login)
      if response.status_code == requests.codes.ok:
          print("Watchdog updated by /alive")
      else:
          print("Failed reseting watchdog")

      print("Wait a second...")
      time.sleep(1)
      response = requests.get("http://" + hostname + "/api/bmc/1.0/" + str(slot_number) + "/watchdog", auth=login)
      if response.status_code == requests.codes.ok:
        response = response.json()
        print("Time left until reset: " + str(response['timeout_left']) + ' ms')
      else:
        print("Failed getting watchdog status")

      request = {"timeout": 0 }
      response = requests.post("http://" + hostname + "/api/bmc/1.0/" + str(slot_number) + "/watchdog", json=request, auth=login)
      if response.status_code == requests.codes.ok:
        print("Watchdog disabled")
      else:
        print("Failed disabling watchdog")

      response = requests.get("http://" + hostname + "/api/bmc/1.0/" + str(slot_number) + "/reset", auth=login)
      if response.status_code == requests.codes.ok:
        print("Successfully reset device after test")
      print("")
    else:
      print("Error response for slot " + str(device['slot_number']))
else:
  print("Error response")

Output:

Watchdog config for BMC on slot 0:
Successfully reset device
Watchdog enabled with timeout 2000ms
Watchdog updated by /alive
Wait a second...
Time left until reset: 981 ms
Watchdog disabled
Successfully reset device after test

5 - Power Module

Power Module RESTful API documentation

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
You may also want to use the secure protocol https://.

Generic

Base URL:

<HOSTNAME>/api/power/<version>/

Version check and device selection

See Version check and device selection

Error response

See Error Response

Source

GET /source

Returns the power sourcing capabilities of the device.

The source_* value shows the maximum power that can be consumed on this voltage rail in milliwatt.
The source_total value shows the maximum power all rails can consume together.
The efficiency_factor* can be used to calculate the power consumption including power dissipation.
e.g: Efficiency is 90% →value is 10W → calculated dissipation is 1W → total consumption is 11W

Request:

Method: GET
URL: <HOSTNAME>/api/power/<version>/<slot>/source

Parameters:

No body parameters

Response:

{
  "source_3v3": <mW>,
  "source_5v0": <mW>,
  "source_12v": <mW>,
  "source_total": <mW>,
  "efficiency_factor_3v3": <int(%)>,
  "efficiency_factor_5v0": <int(%)>,
  "efficiency_factor_12v": <int(%)>
}

Example

Request:

curl http://localhost/api/power/1.0/1/source

Response:

{
  "source_3v3": 17671,
  "source_5v0": 22275,
  "source_12v": 28750,
  "source_total": 28750,
  "efficiency_factor_3v3": 90,
  "efficiency_factor_5v0": 90,
  "efficiency_factor_12v": 100
}

Protection log

GET /protectionlog

Returns the internal protection table counters of the device. If an error like an over voltage event occurs the counter is increased. It can be reset by the factory reset command.

Label explanation:

opp_protection_cnt = Sum of all counters
ovp* = Over voltage protection
uvp* = Under voltage protection
pmc_temperature = Power Management Controller temperature exceeded 125°C
total_power_overload = Total power limit of the device exceeded (see /source)

Voltage limits:

3V3 rail = 3.240V - 3.440V
5V0 rail = 4.608V - 5.202V
12V rail = 11.30V - 12.77V

Request:

Method: GET
URL: <HOSTNAME>/api/power/<version>/<slot>/protectionlog

Parameters:

No body parameters

Response:

{
  "opp_protection_cnt": <int>,
  "ovp_cnt_3v3": <int>,
  "uvp_cnt_3v3": <int>,
  "ovp_cnt_5v0": <int>,
  "uvp_cnt_5v0": <int>,
  "ovp_cnt_12v": <int>,
  "uvp_cnt_12v": <int>,
  "ocp_cnt_3v3": <int>,
  "ocp_cnt_5v0": <int>,
  "ocp_cnt_12v": <int>,
  "pmc_temperature": <int>,
  "total_power_overload": <int>
}

Example

Request:

curl http://localhost/api/power/1.0/1/protectionlog

Response:

{
  "opp_protection_cnt": 0,
  "ovp_cnt_3v3": 0,
  "uvp_cnt_3v3": 0,
  "ovp_cnt_5v0": 0,
  "uvp_cnt_5v0": 0,
  "ovp_cnt_12v": 0,
  "uvp_cnt_12v": 0,
  "ocp_cnt_3v3": 0,
  "ocp_cnt_5v0": 0,
  "ocp_cnt_12v": 0,
  "pmc_temperature": 0,
  "total_power_overload": 0
}

Stats

GET /stats

Returns the voltage and current statistics of the device.

Request:

Method: GET
URL: <HOSTNAME>/api/power/<version>/<slot>/stats

Parameters:

No body parameters

Response:

{
  "voltage_3v3": <mV>,
  "voltage_5v0": <mV>,
  "voltage_12v": <mV>,
  "current_3v3": <mA>,
  "current_5v0": <mA>,
  "current_12v": <mA>,
  "limit_3v3": <mA>,
  "limit_5v0": <mA>,
  "limit_12v": <mA>
}

Example

Request:

curl http://localhost/api/power/1.0/1/stats

Response:

{
  "voltage_3v3": 3301,
  "voltage_5v0": 4936,
  "voltage_12v": 11936,
  "current_3v3": 762,
  "current_5v0": 536,
  "current_12v": 1,
  "limit_3v3": 5950,
  "limit_5v0": 4950,
  "limit_12v": 2400
}

Limits

POST /limits

Enables the watchdog timeout. The timeout is disabled after reset if the config is not saved.

“limit_3v3” must be > 1000 and < 5950 mA

“limit_5v0” must be > 1000 and < 4950 mA

“limit_12v” must be > 100 and < 2400 mA

Request:

Method: POST
URL: <HOSTNAME>/api/power/<version>/<slot>/limits

Parameters:

{
  "limit_3v3": <int>,
  "limit_5v0": <int>,
  "limit_12v": <int>
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/power/1.0/1/limits --header "Content-Type: application/json" --request POST --data '{"limit_3v3": 5950, "limit_5v0": 4950, "limit_12v": 2400}'

Response:

{
  "status": "success"
}

Temperature

GET /temperature

Returns the temperature value of all sensors.

on_board_temp: Value from the NTC located next to the AC/DC converter

pmc_temp: Value from the PMCs internal sensor

The unit is degree Celsius.

Request:

Method: GET
URL: <HOSTNAME>/api/power/<version>/<slot>/temperature

Parameters:

No body parameters

Response:

{
  "on_board_temp": <float>,
  "pmc_temp": <float>
}

Example

Request:

curl http://localhost/api/power/1.0/1/temperature

Response:

{
  "on_board_temp": 40.353,
  "pmc_temp": 36.632
}

Fan

If the fan mode is changed it may take up to 10 seconds until it is applied by the firmware (to prevent fan vibrations).
fan_setting_mode and fan_current_mode can be compared to check the execution status.

GET /fan

Returns the fan statistics.

fan_forced: False means the fan is auto controlled by the firmware. True means the setting from fan_setting mode is applied.

fan_current_mode: Shows the mode currently in use (in auto and manual mode)

fan_setting_mode: Shows the mode which will be applied if fan_forced is True.

fan_*_mode values: 0, 20, 40, 60, 80, 100 (percent)

Request:

Method: GET
URL: <HOSTNAME>/api/power/<version>/<slot>/fan

Parameters:

No body parameters

Response:

{
  "fan_forced": <bool>,
  "fan_current_mode": <int>,
  "fan_setting_mode": <int>
}

Example

Request:

curl http://localhost/api/power/1.0/1/fan

Response:

{
  "fan_forced": false,
  "fan_current_mode": 0,
  "fan_setting_mode": 80
}

POST /fan

Changes the fan mode to the configured setting.

fan_*_mode values: 0, 20, 40, 60, 80, 100 (percent)

Request:

Method: POST
URL: <HOSTNAME>/api/power/<version>/<slot>/fan

Parameters:

{
  "fan_forced": <bool>,
  "fan_mode": <int>
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/power/1.0/1/fan --header "Content-Type: application/json" --request POST --data '{"fan_forced": true, "fan_mode": 100}'

Response:

{
  "status": "success"
}

RPM

GET /fan/rpm

Returns the fan rounds-per-minute value.
It takes at least a second to update the value after the fan mode changed.

The typical maximum value is 5000 RPM +/- 15%.

Request:

Method: GET
URL: <HOSTNAME>/api/power/<version>/<slot>/fan/rpm

Parameters:

No body parameters

Response:

{
  "enabled": <bool>,
  "rpm": <int>
}

Example

Request:

curl http://localhost/api/power/1.0/1/fan/rpm

Response:

{
  "enabled": false,
  "rpm": 0
}

POST /fan/rpm

Changes the fan rounds-per-minute measurement status.

Request:

Method: POST
URL: <HOSTNAME>/api/power/<version>/<slot>/fan/rpm

Parameters:

{
  "measurement_enabled": <bool>
}

Response:

{
  "status": "success"
}

Example

Request:

curl http://localhost/api/power/1.0/1/fan/rpm --header "Content-Type: application/json" --request POST --data '{"measurement_enabled": true}'

Response:

{
  "status": "success"
}

5.1 - Power Module examples

Basic usage examples

These examples are meant to be run on the device!
If you want to run them from a remote computer, you need to change “localhost” to the IP/hostname.
You will also need to generate an access token and use the “auth basic” method.
You may also want to use the secure protocol https://.

Python examples

Get voltage, current and power

Example:

import requests

base_url = "http://localhost/api/power/1.0/"
# For tokens see http://noreya-nexus.local/nexuscontrolui/system/settings#access-token
login = ("token","")

resp = requests.get(base_url, auth=login)
if resp.status_code == requests.codes.ok:
  response = resp.json()
  for device in response['devices']:
    print("Voltage, current and power values for Power Module on slot " + str(device['slot_number']) + ":")
    resp = requests.get(base_url + str(device['slot_number']) + "/stats", auth=login)
    if resp.status_code == requests.codes.ok:
      response = resp.json()
      voltage_3v3 = round(response['voltage_3v3']/1000,3)
      voltage_5v0 = round(response['voltage_5v0']/1000,3)
      voltage_12v = round(response['voltage_12v']/1000,3)

      current_3v3 = round(response['current_3v3']/1000,3)
      current_5v0 = round(response['current_5v0']/1000,3)
      current_12v = round(response['current_12v']/1000,3)

      power_3v3 = round(voltage_3v3*current_3v3,3)
      power_5v0 = round(voltage_5v0*current_5v0,3)
      power_12v = round(voltage_12v*current_12v,3)

      print("3V3 rail voltage/current/power: " + str(voltage_3v3) + "V * " + str(current_3v3) + "A = " + str(power_3v3) + "W")
      print("5V0 rail voltage/current/power: " + str(voltage_5v0) + "V * " + str(current_5v0) + "A = " + str(power_5v0) + "W")
      print("12V rail voltage/current/power: " + str(voltage_12v) + "V * " + str(current_12v) + "A = " + str(power_12v) + "W")
    else:
      print("Error response for slot " + str(device['slot_number']))
else:
  print("Error response")

Output:

Voltage, current and power values for Power Module on slot 1:
3V3 rail voltage/current/power: 3.302V * 0.585A = 1.932W
5V0 rail voltage/current/power: 4.938V * 0.397A = 1.96W
12V rail voltage/current/power: 11.945V * 0.002A = 0.024W

Fan control

Example:

import requests
import time

base_url = "http://localhost/api/power/1.0/"
# For tokens see http://noreya-nexus.local/nexuscontrolui/system/settings#access-token
login = ("token","")

def check_fan(slot_number):
  response = requests.get(base_url + str(slot_number) + "/fan", auth=login)
  if response.status_code == requests.codes.ok:
    response = response.json()
    if response['fan_forced']:
      print("Fan is controlled by the driver")
    else:
      print("Fan is controlled by the firmware")

    print("Fan speed is: " + str(response['fan_current_mode']) + '%')
    print("Fan setting is: " + str(response['fan_setting_mode']) + '%')

    if (response['fan_current_mode'] != response['fan_setting_mode']) and response['fan_forced']:
        print ("Fan setting is going to be applied within 10 seconds")
        return True
    elif response['fan_forced']:
      print ("Fan setting applied!")
      print ("")
    return False
  else:
    raise RuntimeError("Could not get fan status")

response = requests.get(base_url, auth=("", ""))
if response.status_code == requests.codes.ok:
  response = response.json()
  for device in response['devices']:
    slot_number = device['slot_number']
    print("Fan control for Power Module on slot " + str(slot_number) + ":")

    response = requests.get(base_url + str(slot_number) + "/reset", auth=login)
    if response.status_code == requests.codes.ok:
      print("Successfully reset device")  # We do "write" requests so we need to get a defined state

    request = {"measurement_enabled": True}
    response = requests.post(base_url + str(slot_number) + "/fan/rpm", json=request, auth=login)
    if response.status_code == requests.codes.ok:
      print("Fan rpm measurement enabled")
    else:
      print("Enabling RPM measurement failed")

    check_fan(slot_number)
    print("")

    request = {"fan_forced": True, "fan_mode": 100}
    response = requests.post(base_url + str(slot_number) + "/fan", json=request, auth=login)
    if response.status_code == requests.codes.ok:
      print("Fan speed set to 100%")
      while check_fan(slot_number):  # Worst case it can take 10 seconds until the mode changes!
        time.sleep(1)
    else:
      print("Could not set fan mode")

    time.sleep(2) # It takes at least a second before the RPM value is available
    response = requests.get(base_url + str(slot_number) + "/fan/rpm", auth=login)
    if response.status_code == requests.codes.ok:
      response = response.json()
      print("Fan rounds-per-minutes: " + str(response['rpm']))
    else:
      print("Could not get fan rpm value")

    response = requests.get(base_url + str(slot_number) + "/reset", auth=login)
    if response.status_code == requests.codes.ok:
      print("Successfully reset device")

else:
  print("Error response")

Output:

Fan control for Power Module on slot 1:
Successfully reset device
Fan rpm measurement enabled
Fan is controlled by the firmware
Fan speed is: 0%
Fan setting is: 100%

Fan speed set to 100%
Fan is controlled by the driver
Fan speed is: 0%
Fan setting is: 100%
Fan setting is going to be applied within 10 seconds
Fan is controlled by the driver
Fan speed is: 0%
Fan setting is: 100%
Fan setting is going to be applied within 10 seconds
Fan is controlled by the driver
Fan speed is: 0%
Fan setting is: 100%
Fan setting is going to be applied within 10 seconds
Fan is controlled by the driver
Fan speed is: 100%
Fan setting is: 100%
Fan setting applied!

Fan rounds-per-minutes: 4500
Successfully reset device

6 - Versioning

API versioning schema

The following versioning schema is used for all APIs.

Base URL

<HOSTNAME>/api/<module>/<version>

Examples:

<HOSTNAME>/api/power/0.1/
<HOSTNAME>/api/io/1.0/
<HOSTNAME>/api/bmc/0.11/

Versioning schema

The versioning schema follows the https://semver.org/ guidelines (MAJOR.MINOR.PATCH).

MAJOR The major number is increased if the API has incompatible changes. This version MUST be checked by all clients before using the API.

MINOR The minor number indicates that additional endpoints have been added to the API.

PATCH The patch number is incremented if non compatibility breaking changes are made.
It is not part of the URL but can be checked by using the /version endpoint.