Jump to content

SENSBLUE ATLAS: Difference between revisions

From ATRONIA Wiki
No edit summary
No edit summary
 
(55 intermediate revisions by the same user not shown)
Line 654: Line 654:
login <not needed>  
login <not needed>  


=== 25. Relay Outputs Actor ===
==== <big>24.1 Relay Outputs Actor</big> ====


==== 25.1 App Interfacing ====
===== 24.1.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credentials.
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credentials.


===== 25.1.1 Set/reset digital output pin/pins state =====
====== a) Set/reset digital output pin/pins state ======
Both relays '''default''' state is '''open'''.  
Both relays '''default''' state is '''open'''.  


Req-Topic: relayOutputs/config/in
Req-Topic: relayOutputs/config/in


<syntaxhighlight lang="json">
<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 681: Line 681:
</syntaxhighlight>Reply-Topic: relayOutputs/config/out
</syntaxhighlight>Reply-Topic: relayOutputs/config/out


<syntaxhighlight lang="json">{
<syntaxhighlight lang="json" line="1">{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
   "origin": "APP",
   "origin": "APP",
Line 698: Line 698:
}</syntaxhighlight>
}</syntaxhighlight>


===== 25.1.2 Get all relays state =====
====== b) Get all relays state ======
Req-Topic: relayOutputs/runtime/in<syntaxhighlight lang="json">
 
Req-Topic: relayOutputs/runtime/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 707: Line 708:
   }
   }
}
}
</syntaxhighlight>Reply-Topic: relayOutputs/runtime/out <syntaxhighlight lang="json">
</syntaxhighlight>Reply-Topic: relayOutputs/runtime/out <syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 726: Line 727:
</syntaxhighlight>
</syntaxhighlight>


===== 25.1.3 Set all relays state =====
====== c) Set all relays state ======
Req-Topic: relayOutputs/runtime/in<syntaxhighlight lang="json">
 
Req-Topic: relayOutputs/runtime/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 743: Line 745:
   }
   }
}
}
</syntaxhighlight>Reply-Topic: relayOutputs/runtime/out<syntaxhighlight lang="json">
</syntaxhighlight>Reply-Topic: relayOutputs/runtime/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 762: Line 764:
</syntaxhighlight>
</syntaxhighlight>


=== 26. RTC Actor ===
==== <big>24.2 RTC Actor</big> ====


==== 26.1 App Interfacing ====
===== 24.2.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.


===== 26.1.1 Set timer/alarm interruption =====
====== a) Set timer/alarm interruption ======
'''mode:''' Timer, alarm or none.
'''mode:''' Timer, alarm or none.


Line 774: Line 776:
'''timerSetSeconds:''' Period in seconds for timer interruption (No effect if mode is alarm or none).
'''timerSetSeconds:''' Period in seconds for timer interruption (No effect if mode is alarm or none).


Req-Topic: clock/config/in<syntaxhighlight lang="json">
Req-Topic: clock/config/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 788: Line 790:
   }
   }
}
}
</syntaxhighlight>Req-Topic: clock/config/out<syntaxhighlight lang="json">
</syntaxhighlight>Req-Topic: clock/config/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 805: Line 807:
</syntaxhighlight>
</syntaxhighlight>


===== 26.1.2 Toggle RTC sync logic (described below) =====
====== b) Toggle RTC sync logic (described below) ======
'''tcState:''' State of the synchronization logic of the RTC, this value is '''non-persistent''' so every-time a reboot happens the value return to default (by default the value is '''ON''')
'''tcState:''' State of the synchronization logic of the RTC, this value is '''non-persistent''' so every-time a reboot happens the value return to default (by default the value is '''ON''')


Req-Topic: clock/config/in<syntaxhighlight lang="json">
Req-Topic: clock/config/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 816: Line 818:
   }
   }
}
}
</syntaxhighlight>Req-Topic: clock/config/out<syntaxhighlight lang="json">
</syntaxhighlight>Req-Topic: clock/config/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 830: Line 832:
</syntaxhighlight>
</syntaxhighlight>


===== 26.1.3 Read clock configs =====
====== c) Read clock configs ======
'''mode:''' Timer, alarm or none.
'''mode:''' Timer, alarm or none.


Line 839: Line 841:
'''rtcState:''' Current state of the synchronization logic of the RTC.
'''rtcState:''' Current state of the synchronization logic of the RTC.


Req-Topic: clock/config/in<syntaxhighlight lang="json">
Req-Topic: clock/config/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 848: Line 850:
}
}


</syntaxhighlight>Reply-Topic: clock/config/out<syntaxhighlight lang="json">
</syntaxhighlight>Reply-Topic: clock/config/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 867: Line 869:
</syntaxhighlight>
</syntaxhighlight>


===== 26.1.4 Read clock =====
====== d) Read clock ======
Req-Topic: clock/runtime/in <syntaxhighlight lang="json">
 
Req-Topic: clock/runtime/in <syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 882: Line 885:
</syntaxhighlight>
</syntaxhighlight>


==== 26.2 Synchronization loop flowchart (every 30 seconds) ====
===== 24.2.2 Synchronization loop flowchart (every 30 seconds) =====




'''RTC Actor - Overview'''
'''RTC Actor - Overview'''
[[File:RTCActor Overview.svg|center|frameless|774x774px]]
[[File:RTCActor Overview.svg|center|frameless|903x903px]]


=== 27. Core System Health Actor ===
==== <big>24.3 Core System Health Actor</big> ====


==== 27.1 App Interfacing ====
===== 24.3.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker.
User App interface and functionalities exposed to the open part of the MQTT broker.


This interface allows any external App to receive system-level metrics such as CPU load, RAM usage, disk usage, temperature, core frequency, system throttle status and uptime. No credentials are required to subscribe to this topic. The System Health Actor does not receive commands. It is fully autonomous and publishes its metrics every 1 second.
This interface allows any external App to '''receive system-level metrics''' such as CPU load, RAM usage, disk usage, temperature, core frequency, system throttle status and uptime.
 
No credentials are required to subscribe to this topic.
 
The System Health Actor '''does not receive commands'''. It is fully autonomous and publishes its metrics every '''1 second'''.


==== 27.2 Runtime Data ====
===== 24.3.2 Runtime Data =====
'''Topic: systemHea l th/runtime/ out'''
'''Topic: systemHealth/runtime/out'''


Publish rate: '''1 Hz''' (one message per second, clock-jump safe)
Publish rate: '''1 Hz''' (one message per second, clock-jump safe)


===== 27.2.1 Metrics Provided =====
====== a) Metrics Provided ======
{| class="wikitable tech-table"
{| class="wikitable tech-table"
!'''Key'''
!'''Key'''
Line 946: Line 953:
|seconds
|seconds
|}
|}
Example Payload (systemHealth/runtime/out) <syntaxhighlight lang="json">
Example Payload (systemHealth/runtime/out) <syntaxhighlight lang="json" line="1">
{
{
   "id": 1736022028123,
   "id": <TIMESTAMP>,
   "origin": "system-health",
   "origin": "system-health",
   "task": {
   "task": {
Line 968: Line 975:
</syntaxhighlight>
</syntaxhighlight>


==== 27.3 Peripherals health ====
===== 24.3.3 Peripherals health =====
  In order get the peripherals health we had to implement a SystemHealth actor in each bus manager (busi2c­O, busi2c-1, etc. ... ).
  In order get the peripherals health we had to implement a SystemHealth actor in each bus manager (busi2c­O, busi2c-1, etc. ... ).


Line 974: Line 981:
[[File:Peripherals health.svg|center|frameless|792x792px]]
[[File:Peripherals health.svg|center|frameless|792x792px]]


===== 27.3.1 Example =====
====== a) Example ======
'''For busi2c-0:'''
'''For busi2c-0:'''


Reply topic: '''systemHealth/busi2c-0/runtime/out'''  
Reply topic: '''systemHealth/busi2c-0/runtime/out'''  


Payload:<syntaxhighlight lang="json">
Payload:<syntaxhighlight lang="json" line="1">
{
{
   "id": 1770378753024,
   "id": <TIMESTAMP>,
   "origin": "system-health-busi2c-0",
   "origin": "system-health-busi2c-0",
   "task": {
   "task": {
Line 1,059: Line 1,066:
Reply topic: '''systemHealth/busi2c-1/runtime/out'''  
Reply topic: '''systemHealth/busi2c-1/runtime/out'''  


Payload:<syntaxhighlight lang="json">
Payload:<syntaxhighlight lang="json" line="1">
{
{
   "id": 1770382405107,
   "id": <TIMESTAMP>,
   "origin": "system-health-busi2c-1",
   "origin": "system-health-busi2c-1",
   "task": {
   "task": {
Line 1,181: Line 1,188:
</syntaxhighlight>
</syntaxhighlight>


=== 28. TempSensor Actor ===
===== 24.3.4 Commands =====


==== 28.1 App Interfacing ====
====== a) List usb devices ======
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
The list_usb_devices action returns a parsed list of USB devices detected on the system using the lsusb command.  


===== 28.1.1 Set temperature sensor configurations =====
'''Req-topic''': systemHealth/runtime/in<syntaxhighlight lang="json" line="1">
Req-Topic: tempSensor/config/in
{
 
"id": <TIMESTAMP>,
ALERT:
"origin": "Dev",
 
"task": {
* activate: true(active)/false
  "action": "LIST_USB_DEVICES"
* templow: alert temperature lower limit
}
* tempHigh: alert temperature upper limit
}
<syntaxhighlight lang="json">
</syntaxhighlight>'''Reply-topic''': systemHealth/runtime/usb/devices/out<syntaxhighlight lang="json" line="1">
{
{
  "id": "<TIMESTAMP>",
"id": <TIMESTAMP>,
   "origin": "APP",
"origin": "system-health",
   "task": {
"task": {
    "taskParams": {
   "action": "list_usb_devices",
      "ALERT": {
   "taskResult": {
        "activate": true,
    "usb_devices": {
        "tempLow": 0,
      "success": true,
        "tempHigh": 80
      "command": "lsusb",
      }
      "returncode": 0,
    }
      "devices": [
  }
        {
}
          "bus": "001",
</syntaxhighlight>Reply-Topic: tempSensor/config/out<syntaxhighlight lang="json">
          "device": "001",
{
          "vendor_id": "1d6b",
  "id": "<TIMESTAMP>",
          "product_id": "0002",
  "origin": "APP",
          "description": "Linux Foundation 2.0 root hub",
  "task": {
          "parsed": true
    "taskResult": {
        },
      "success": true,
        {
      "ALERT": {
          "bus": "001",
        "activate": true,
          "device": "002",
        "tempLow": 0,
          "vendor_id": "0424",
        "tempHigh": 80
          "product_id": "9514",
          "description": "Microchip Technology, Inc. (formerly SMSC) SMC9514 Hub",
          "parsed": true
        },
        {
          "bus": "001",
          "device": "003",
          "vendor_id": "0424",
          "product_id": "ec00",
          "description": "Microchip Technology, Inc. (formerly SMSC) SMSC9512/9514 Fast Ethernet Adapter",
          "parsed": true
        },
        {
          "bus": "001",
          "device": "004",
          "vendor_id": "1e0e",
          "product_id": "9001",
          "description": "Qualcomm / Option SimTech, Incorporated",
          "parsed": true
        }
      ],
      "stderr": ""
       }
       }
     }
     }
   }
   }
}
}
</syntaxhighlight>
{| class="wikitable tech-table"
!'''JSON Path'''
!'''Type'''
!Example
!'''Description'''
|-
|id
|string /number
|"get-hw-info-001"
|Request identifier echoed back in the response.
|-
|origin
|string
|"system-health"
|Actor/device that generated the response.
|-
|task
|object
|{...}
|Container for the action response.
|-
|task.action
|string
|"list_usb_devices"
|Action executed by the actor.
|-
|task.taskResult
|object
|{...}
|Main result object for the action.
|-
|task.taskResult.usb_devices
|object
|{...}
|Contains the USB device scan result.
|-
|task.taskResult.usb_devices.success
|boolean
|true
|Indicates whether the lsusb
commandexecuted successfully.
|-
|task.taskResult.usb_devices.command
|string
|"lsusb"
|Command used to collect USB information.
|-
|task.taskResult.usb_devices.returncode
|number /null
|0
|Process return code. 0 means success. null
means the command was not executed ortimed out.
|-
|task.taskResult.usb_devices.devices
|array
|[...]
|List of USB devices detected by lsusb.
|-
|task.taskResult.usb_devices.devices[ ].bus
|string
|"001"
|USB bus number where the device wasdetected.
|-
|task.taskResult.usb_devices.devices[ ].device
|string
|"004"
|USB device number assigned on that bus.
|-
|task.taskResult.usb_devices.devices[ ].vendor_id
|string
|"1e0e"
|USB vendor ID in hexadecimal format.
|-
|task.taskResult.usb_devices.devices[ ].product_id
|string
|"9001"
|USB product ID in hexadecimal format.
|-
|task.taskResult.usb_devices.devices[ ].description
|string
|"Qualcomm / Option SimTech,Incorporated"
|Human-readable device description returnedby lsusb.
|-
|task.taskResult.usb_devices.devices[ ].parsed
|boolean
|true
|Indicates whether the lsusb line was parsed successfully.
|-
|task.taskResult.usb_devices.devices[ ].raw
|string
|Optional
|Present only when a device line could not beparsed.
Contains the original raw lsusb line.
|-
|task.taskResult.usb_devices.stderr
|string
|" "
|Error output from the command. Empty stringmeans no error.
|}


</syntaxhighlight>
====== b) List connectivity specs ======
The list_connectivity_specs action allows the '''SystemHealth''' Actor to return connectivity information for the device, including the status of:


===== 28.1.2 Read temperature sensor configurations =====
* Wi-Fi
Req-Topic: tempSensor/config/in
* LTE modem
* eth0
* eth1
* Tunnel interfaces, for possible commissioning use


ALERT:
'''Req-topic''': systemHealth/runtime/in<syntaxhighlight lang="json" line="1">
 
{
* activate: true(active)/false
"id": "connectivity-001",
 
"origin": "APP",
LIMITS:
"task": {
 
  "action": "list_connectivity_specs"
* templow: alert temperature lower limit
}
* tempHigh: alert temperature upper limit
}
<syntaxhighlight lang="json">
</syntaxhighlight>'''Reply-topic''': systemHealth/runtime/connectivity/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
   "origin": "APP",
   "origin": "system-health",
   "task": {
   "task": {
     "action": "READ"
     "action": "list_connectivity_specs",
    "taskResult": {
      "connectivity": {
        "sources": {
          "sysfs": "/sys/class/net",
          "ip_link": {
            "available": true,
            "command": "ip -j -d link show",
            "error": null
          },
          "network_manager": {
            "available": true,
            "command": "nmcli -t -f DEVICE,TYPE,STATE,CONNECTION device status",
            "error": null
          }
        },
        "interfaces": {
          "wifi": {
            "available": true,
            "interfaces": [
              {
                "interface": "wlan0",
                "available": true,
                "status": "down",
                "operstate": "down",
                "admin_up": true,
                "carrier": false,
                "mtu": 1500,
                "type": 1,
                "link_kind": null,
                "mac_address": "2c:cf:67:fd:60:40",
                "ipv4": [],
                "ipv6": [],
                "network_manager": {
                  "device": "wlan0",
                  "type": "wifi",
                  "state": "disconnected",
                  "connection": null
                },
                "wifi": {
                  "available": true,
                  "command": "iw dev wlan0 link",
                  "connected": false
                }
              }
            ]
          },
          "lte_modem": {
            "available": true,
            "tool_available": true,
            "command": "mmcli -L",
            "modems": [
              {
                "id": "0",
                "success": true,
                "command": "mmcli -m 0 --output-json",
                "manufacturer": "QUALCOMM INCORPORATED",
                "model": "SIMCOM_SIM7600G-H",
                "revision": "LE20B04SIM7600G22",
                "hardware_revision": "10000",
                "device": "/sys/devices/platform/scb/fe9c0000.xhci/usb1/1-1/1-1.4",
                "drivers": [
                  "qmi_wwan",
                  "option"
                ],
                "plugin": "simtech",
                "primary_port": "cdc-wdm0",
                "ports": [
                  {
                    "name": "cdc-wdm0",
                    "type": "qmi"
                  },
                  {
                    "name": "ttyUSB0",
                    "type": "ignored"
                  },
                  {
                    "name": "ttyUSB1",
                    "type": "gps"
                  },
                  {
                    "name": "ttyUSB2",
                    "type": "at"
                  },
                  {
                    "name": "ttyUSB3",
                    "type": "at"
                  },
                  {
                    "name": "ttyUSB4",
                    "type": "audio"
                  },
                  {
                    "name": "wwan0",
                    "type": "net"
                  }
                ],
                "state": "failed",
                "power_state": "on",
                "access_technologies": [],
                "signal_quality": {
                  "recent": "yes",
                  "value": "0"
                },
                "current_capabilities": [
                  "gsm-umts, lte"
                ],
                "supported_capabilities": [
                  "gsm-umts, lte"
                ],
                "operator_code": "--",
                "operator_name": "--",
                "registration_state": "--",
                "packet_service_state": "--",
                "sim_path": null
              }
            ],
            "network_interfaces": [
              {
                "interface": "wwan0",
                "available": true,
                "status": "down",
                "operstate": "down",
                "admin_up": false,
                "carrier": null,
                "mtu": 1500,
                "type": 65534,
                "link_kind": null,
                "mac_address": null,
                "ipv4": [],
                "ipv6": [],
                "network_manager": null
              }
            ]
          },
          "eth0": {
            "interface": "eth0",
            "available": true,
            "status": "connected",
            "operstate": "up",
            "admin_up": true,
            "carrier": true,
            "mtu": 1500,
            "type": 1,
            "link_kind": null,
            "mac_address": "2c:cf:67:fd:60:3f",
            "ipv4": [
              {
                "address": "172.16.20.57",
                "prefixlen": 24,
                "scope": "global",
                "dynamic": true
              }
            ],
            "ipv6": [
              {
                "address": "fe80::7fc1:f65f:5729:d234",
                "prefixlen": 64,
                "scope": "link",
                "dynamic": false
              }
            ],
            "network_manager": {
              "device": "eth0",
              "type": "ethernet",
              "state": "connected",
              "connection": "wired-ip-dynamic"
            }
          },
          "eth1": {
            "interface": "eth1",
            "available": true,
            "status": "unavailable",
            "operstate": "down",
            "admin_up": true,
            "carrier": false,
            "mtu": 1500,
            "type": 1,
            "link_kind": null,
            "mac_address": "2c:cf:67:fd:60:41",
            "ipv4": [],
            "ipv6": [],
            "network_manager": {
              "device": "eth1",
              "type": "ethernet",
              "state": "unavailable",
              "connection": null
            }
          },
          "tunnel": {
            "available": false,
            "interfaces": []
          }
        }
      }
    }
   }
   }
}
}
 
</syntaxhighlight>
</syntaxhighlight>Reply-Topic: tempSensor/config/out<syntaxhighlight lang="json">
{| class="wikitable tech-table"
{
!'''Field'''
  "id": "<TIMESTAMP>",
!'''Type'''
  "origin": "APP",
!'''Description'''
  "task": {
|-
    "taskResult": {
|id
      "success": true,
|string/number
      "ALERT": {
|Request/response identifier used to correlate therequest with the response.
        "activate": true,
|-
        "tempLow": 0,
|origin
        "tempHigh": 80
|string
      }
|Origin of the message. In the response, this is normallythe SystemHealth actor name.
    }
|-
  }
|task.action
}
|string
 
|Executed action. For this feature, the value is list_connectivity_specs.
</syntaxhighlight>
|-
 
|task.taskResult.connectivity.sources.sysfs
===== 28.1.3 Read temperature and alert status =====
|string
 
|Linux sysfs path used to discover network interfaces, usually/sys/class/net.
* unit: Temperature unit of measure
|-
* alert: true (triggered) or false
|task.taskResult.connectivity.sources.ip_link.available
 
|boolean
Req-Topic: tempSensor/runtime/in<syntaxhighlight lang="json">
|Indicates whether the ip command was available andexecuted successfully.
{
|-
  "id": "<TIMESTAMP>",
|task.taskResult.connectivity.sources.ip_link.command
  "origin": "APP",
|string
  "task": {
|Command used to retrieve detailed link information,for example ip -j -d link show.
    "action": "READ"
|-
  }
|task.taskResult.connectivity.sources.ip_link.error
}
|string/null
 
|Error returned by the ip command, or null if no erroroccurred.
</syntaxhighlight>Reply-Topic: tempSensor/runtime/out<syntaxhighlight lang="json">
|-
{
|task.taskResult.connectivity.sources.network_manager.available
  "id": "<TIMESTAMP>",
|boolean
  "origin": "APP",
|Indicates whether NetworkManager / nmcli was available and executed successfully.
  "task": {
|-
    "taskResult": {
|task.taskResult.connectivity.sources.network_manager.command
      "success": true,
|string
      "data": {
|Command used to retrieve NetworkManager device status.
        "temperature": <_FLOAT_>,
|-
        "unit": "C",
|task.taskResult.connectivity.sources.network_manager.error
        "alert": true
|string/null
      }
|Error returned by nmcli, or null if no error occurred.
    }
|-
  }
|task.taskResult.connectivity.interfaces.wifi.available
}
|boolean
 
|Indicates whether at least one Wi-Fi interface was found.
</syntaxhighlight>
|-
 
|task.taskResult.connectivity.interfaces.wifi.interfaces[ ]
=== 29. TFT Actor ===
|array
 
|List of detected Wi-Fi interfaces, usually including '''wlan0''' when Wi-Fi exists.
==== 29.1 App Interfacing ====
|-
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to control and interact with the TFT display, or frontal panel LCD screen. Connecting to the broker for this Area requires no credentials.
|wifi.interfaces[ ].interface
 
|string
==== 29.2 TFT Display Actor ====
|Linux interface name, for example '''wlan0'''.
  The TFT Actor is responsible for:
|-
 
|wifi.interfaces[ ].available
* Rendering static and informative screens on the TFT display
|boolean
* Reacting to joystick input (LEFT/ RIGHT/ CENTER/ UP/ DOWN)
|Indicates whether the Wi-Fi interface exists in the system.
* Managing screen navigation and user confirmation flows
|-
* Providing feedback to the application via MQTT
|wifi.interfaces[ ].status
 
|string
===== 29.2.1 Screen Carousel Concept =====
|Normalized interface status, for example '''connected, down, unavailable, no_carrier,''' or '''not_available'''.
The TFT actor maintains an '''ordered list of screens''' (carousel).
|-
 
|wifi.interfaces[ ].operstate
* Screens are navigated using the joystick:
|string / null
 
|Operational state reported by Linux, for example '''up, down,''' or '''unknown'''.
- LEFT --> Previous screen
|-
 
|wifi.interfaces[ ].admin_up
- RIGHT --> Next screen
|boolean / null
 
|Indicates whether the interface is administratively enabled.
* The carousel wraps around:
|-
 
|wifi.interfaces[ ].carrier
- LEFT on first screen --> last screen
|boolean / null
 
|Indicates whether carrier/link is detected.
- RIGHT on last screen --> first screen
|-
 
|wifi.interfaces[ ].mtu
===== 29.2.2 Screen Types =====
|number / null
The TFT actor supports the following screen types:
|Maximum Transmission Unit of the interface.
 
|-
'''a.) Image Screen'''
|wifi.interfaces[ ].type
 
|number / null
* Displays a static JPEG image
|Linux interface type.
* Default screen shown at boot
|-
* No user interaction required
|wifi.interfaces[ ].link_kind
 
|string / null
'''b.) Network Information Screen'''
|Special link type, used mainly for virtual/tunnel interfaces. Usually null for normal Wi-Fi.
 
|-
* Display a interface with information about the networks of the device
|wifi.interfaces[ ].mac_address
* Updated on load
|string / null
* No user interaction required
|MAC address of the Wi-Fi interface.
 
|-
===== 29.2.3 Joystick Navigation Logic =====
|wifi.interfaces[ ].ipv4[ ]
'''Carousel Navigation:'''
|array
{| class="wikitable"
|List of IPv4 addresses configured on the Wi-Fi interface.
|'''Joystick  Input'''
|-
|'''Action'''
|wifi.interfaces[ ].ipv6[ ]
|array
|List of IPv6 addresses configured on the Wi-Fi interface.
|-
|wifi.interfaces[ ].network_manager.device
|string
|NetworkManager device name.
|-
|wifi.interfaces[ ].network_manager.type
|string
|NetworkManager interface type, usually '''wifi'''.
|-
|wifi.interfaces[ ].network_manager.state
|string
|NetworkManager state, for example '''connected''', '''disconnected''', or '''unavailable'''.
|-
|wifi.interfaces[ ].network_manager.connection
|string / null
|Active NetworkManager profile name, or null if none is active.
|-
|wifi.interfaces[ ].wifi.available
|boolean
|Indicates whether Wi-Fi details could be queried using '''iw'''.
|-
|wifi.interfaces[ ].wifi.command
|string
|Command used to query Wi-Fi link state, for example '''iw dev wlan0 link'''.
|-
|wifi.interfaces[ ].wifi.connected
|boolean / null
|Indicates whether the Wi-Fi interface is associated with a Wi-Fi network.
|-
|wifi.interfaces[ ].wifi.ssid
|string
|SSID of the connected Wi-Fi network, when connected.
|-
|wifi.interfaces[ ].wifi.bssid
|string
|BSSID/MAC address of the connected access point, when connected.
|-
|wifi.interfaces[ ].wifi.frequency_mhz
|number
|Wi-Fi frequency in MHz, when connected.
|-
|wifi.interfaces[ ].wifi.signal_dbm
|number
|Wi-Fi signal strength in dBm, when available.
|-
|wifi.interfaces[ ].wifi.tx_bitrate
|string
|Wi-Fi transmit bitrate, when available.
|-
|wifi.interfaces[ ].wifi.rx_bitrate
|string
|Wi-Fi receive bitrate, when available.
|-
|task.taskResult.connectivity.interfaces.lte_modem.available
|boolean
|Indicates whether at least one LTE modem was detected.
|-
|task.taskResult.connectivity.interfaces.lte_modem.tool_available
|boolean
|Indicates whether '''mmcli''' / ModemManager is available.
|-
|task.taskResult.connectivity.interfaces.lte_modem.command
|string
|Command used to list LTE modems, usually '''mmcli -L'''.
|-
|task.taskResult.connectivity.interfaces.lte_modem.modems[ ]
|array
|List of LTE modems detected by ModemManager.
|-
|lte_modem.modems[ ].id
|string
|Modem ID in ModemManager, for example '''0'''.
|-
|lte_modem.modems[ ].success
|boolean
|Indicates whether detailed modem information wasread successfully.
|-
|lte_modem.modems[ ].command
|string
|Command used to read modem details, for example '''mmcli -m 0 --output-json'''.
|-
|lte_modem.modems[ ].manufacturer
|string / null
|Modem manufacturer.
|-
|lte_modem.modems[ ].model
|string / null
|Modem model.
|-
|lte_modem.modems[ ].revision
|string / null
|Modem firmware/software revision.
|-
|lte_modem.modems[ ].hardware_revision
|string / null
|Modem hardware revision.
|-
|lte_modem.modems[ ].device
|string / null
|Sysfs/USB path of the modem device.
|-
|lte_modem.modems[ ].drivers[ ]
|array
|Linux drivers associated with the modem, for example '''qmi_wwan''' or '''option'''.
|-
|lte_modem.modems[ ].plugin
|string / null
|ModemManager plugin used to manage the modem.
|-
|lte_modem.modems[ ].primary_port
|string / null
|Primary modem control port, for example '''cdc-wdm0'''.
|-
|lte_modem.modems[ ].ports[ ]
|array
|List of ports associated with the modem.
|-
|lte_modem.modems[ ].ports[ ].name
|string
|Port/interface name, for example '''cdc-wdm0''', '''ttyUSB2''', or '''wwan0'''.
|-
|lte_modem.modems[ ].ports[ ].type
|string / null
|Port type, for example '''qmi, at, gps, audio, net''', or '''ignored'''.
|-
|lte_modem.modems[ ].state
|string / null
|General modem state according to ModemManager,for example '''registered''', '''connected''', or '''failed'''.
|-
|lte_modem.modems[ ].power_state
|string / null
|Modem power state, for example '''on, off''', or '''low'''.
|-
|lte_modem.modems[ ].access_technologies[ ]
|array
|Current access technologies in use, for example LTE,UMTS, or GSM.
|-
|lte_modem.modems[ ].signal_quality.recent
|string / null
|Indicates whether the signal quality value is recent.
|-
|lte_modem.modems[ ].signal_quality.value
|string / number / null
|Signal quality value reported by the modem.
|-
|lte_modem.modems[ ].current_capabilities[ ]
|array
|Current modem capabilities.
|-
|lte_modem.modems[ ].supported_capabilities[ ]
|array
|Capabilities supported by the modem.
|-
|lte_modem.modems[ ].operator_code
|string / null
|MCC/MNC operator code.
|-
|lte_modem.modems[ ].operator_name
|string / null
|Operator name.
|-
|lte_modem.modems[ ].registration_state
|string / null
|Mobile network registration state.
|-
|lte_modem.modems[ ].packet_service_state
|string / null
|Mobile packet data service state.
|-
|lte_modem.modems[ ].sim_path
|string / null
|SIM path in ModemManager, when available.
|-
|task.taskResult.connectivity.interfaces.lte_modem.network_interfaces[]
|array
|List of Linux network interfaces associated with the LTE modem, usually '''wwan0'''.
|-
|lte_modem.network_interfaces[ ].interface
|string
|LTE network interface name, for example '''wwan0'''.
|-
|lte_modem.network_interfaces[ ].available
|boolean
|Indicates whether the LTE network interface exists.
|-
|-
|LEFT
|lte_modem.network_interfaces[ ].status
|Previous screen
|string
|Normalized LTE network interface status.
|-
|-
|RIGHT
|lte_modem.network_interfaces[ ].operstate
|Next screen
|string / null
|Operational state reported by Linux.
|-
|-
|DOWN
|lte_modem.network_interfaces[ ].admin_up
|Refresh current screen
|boolean / null
|}
|Indicates whether the LTE network interface is administratively enabled.
 
|-
===== 29.2.4 Boot Behavior =====
|lte_modem.network_interfaces[ ].carrier
At system boot:
|boolean / null
 
|Indicates whether carrier/link information is availableand active.
# TFT actor initializes the display
|-
# Last available carousel is loaded
|lte_modem.network_interfaces[ ].mtu
# First screen is rendered
|number / null
# Joystick subscriptions are activated
|Maximum Transmission Unit of the LTE network interface.
# Actor waits for runtime commands
|-
 
|lte_modem.network_interfaces[ ].type
===== 29.2.5 Design Notes & Constraints =====
|number / null
 
|Linux interface type.
* TFT actor does not expose joystick state
|-
* Joystick actor remains independent
|lte_modem.network_interfaces[ ].link_kind
* TFT actor internally consumes joystick events
|string / null
* Carousel state is local to the TFT actor
|Link kind, when available.
* Screen rendering is synchronous; input handling is asynchronous
|-
* Confirmation screens always require explicit CENTER press
|lte_modem.network_interfaces[ ].mac_address
 
|string / null
==== 29.3 User interaction through MQTT ====
|MAC address, when available.
Enabling interaction with the carousel using the topic tft/runtime/in . Actions available will be public to the user.
|-
 
|lte_modem.network_interfaces[ ].ipv4[ ]
'''Runtime commands'''
|array
 
|IPv4 addresses configured on the LTE network interface.
'''Go to screen'''
|-
 
|lte_modem.network_interfaces[ ].ipv6[ ]
Req-Topic: tft/runtime/in<syntaxhighlight lang="json">
|array
{
|IPv6 addresses configured on the LTE network interface.
  "id": "<TIMESTAMP>",
|-
  "origin": "APP",
|lte_modem.network_interfaces[ ].network_manager
  "task": {
|object / null
    "action": "SET_CAROUSEL",
|NetworkManager information for the LTE interface, when available.
    "params": {
|-
      "index": 2
|task.taskResult.connectivity.interfaces.eth0.interface
    }
|string
  }
|Ethernet interface name, '''eth0'''.
}
|-
|task.taskResult.connectivity.interfaces.eth0.available
|boolean
|Indicates whether '''eth0''' exists.
|-
|task.taskResult.connectivity.interfaces.eth0.status
|string
|Normalized '''eth0''' status.
|-
|task.taskResult.connectivity.interfaces.eth0.operstate
|string / null
|Operational state of '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth0.admin_up
|boolean / null
|Indicates whether '''eth0''' is administratively enabled.
|-
|task.taskResult.connectivity.interfaces.eth0.carrier
|boolean / null
|Indicates whether '''eth0''' has physical link.
|-
|task.taskResult.connectivity.interfaces.eth0.mtu
|number / null
|MTU of '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth0.type
|number / null
|Linux interface type of '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth0.link_kind
|string / null
|Link kind of '''eth0''', usually '''null'''.
|-
|task.taskResult.connectivity.interfaces.eth0.mac_address
|string / null
|MAC address of '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth0.ipv4[ ]
|array
|IPv4 addresses configured on '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth0.ipv6[ ]
|array
|IPv6 addresses configured on '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth0.network_manager
|object / null
|NetworkManager information for '''eth0'''.
|-
|task.taskResult.connectivity.interfaces.eth1.interface
|string
|Ethernet interface name, '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.available
|boolean
|Indicates whether '''eth1''' exists.
|-
|task.taskResult.connectivity.interfaces.eth1.status
|string
|Normalized '''eth1''' status.
|-
|task.taskResult.connectivity.interfaces.eth1.operstate
|string / null
|Operational state of '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.admin_up
|boolean / null
|Indicates whether '''eth1''' is administratively enabled.
|-
|task.taskResult.connectivity.interfaces.eth1.carrier
|boolean / null
|Indicates whether '''eth1''' has physical link.
|-
|task.taskResult.connectivity.interfaces.eth1.mtu
|number / null
|MTU of '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.type
|number / null
|Linux interface type of '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.link_kind
|string / null
|Link kind of '''eth1''', usually '''null'''.
|-
|task.taskResult.connectivity.interfaces.eth1.mac_address
|string / null
|MAC address of '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.ipv4[ ]
|array
|IPv4 addresses configured on '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.ipv6[ ]
|array
|IPv6 addresses configured on '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.eth1.network_manager
|object / null
|NetworkManager information for '''eth1'''.
|-
|task.taskResult.connectivity.interfaces.tunnel.available
|boolean
|Indicates whether at least one tunnel interface was detected.
|-
|task.taskResult.connectivity.interfaces.tunnel.interfaces[ ]
|array
|List of detected tunnel interfaces, for example '''tun0, tap0, wg0''', or '''tailscale0'''.
|-
|tunnel.interfaces[ ].interface
|string
|Tunnel interface name.
|-
|tunnel.interfaces[ ].available
|boolean
|Indicates whether the tunnel interface exists.
|-
|tunnel.interfaces[ ].status
|string
|Normalized tunnel interface status.
|-
|tunnel.interfaces[ ].operstate
|string / null
|Operational state reported by Linux.
|-
|tunnel.interfaces[ ].admin_up
|boolean / null
|Indicates whether the tunnel interface isadministratively enabled.
|-
|tunnel.interfaces[ ].carrier
|boolean / null
|Carrier/link information, when available.
|-
|tunnel.interfaces[ ].mtu
|number / null
|Tunnel interface MTU.
|-
|tunnel.interfaces[ ].type
|number / null
|Linux interface type.
|-
|tunnel.interfaces[ ].link_kind
|string / null
|Tunnel link kind, for example '''tun, tap''', or '''wireguard'''.
|-
|tunnel.interfaces[ ].mac_address
|string / null
|MAC address, when available.
|-
|tunnel.interfaces[ ].ipv4[ ]
|array
|IPv4 addresses configured on the tunnel interface.
|-
|tunnel.interfaces[ ].ipv6[ ]
|array
|IPv6 addresses configured on the tunnel interface.
|-
|tunnel.interfaces[ ].network_manager
|object / null
|NetworkManager information for the tunnel interface, when available.
|-
|ipv4[ ].address
|string
|IPv4 address assigned to the interface.
|-
|ipv4[ ].prefixlen
|number
|IPv4 network prefix length. Example: '''24'''.
|-
|ipv4[ ].scope
|string
|IPv4 scope, for example '''global'''.
|-
|ipv4[ ].dynamic
|boolean
|Indicates whether the IPv4 address was dynamically assigned.
|-
|ipv6[ ].address
|string
|IPv6 address assigned to the interface.
|-
|ipv6[ ].prefixlen
|number
|IPv6 network prefix length.
|-
|ipv6[ ].scope
|string
|IPv6 scope, for example '''link''' or '''global'''.
|-
|ipv6[].dynamic
|boolean
|Indicates whether the IPv6 address was dynamically assigned.
|}


</syntaxhighlight>Reply-Topic: tft/runtime/out<syntaxhighlight lang="json">
====== c) Get hardware info ======
'''Req-topic''': systemHealth/runtime/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
   "origin": "tft",
   "origin": "Dev",
   "task": {
   "task": {
     "taskResult": {
     "action": "GET_HW_INFO"
      "success": true,
      "index": 2
    }
   }
   }
}
}
 
</syntaxhighlight>'''Reply-topic''': systemHealth/runtime/hw/info/out<syntaxhighlight lang="json" line="1">
</syntaxhighlight>'''Set TFT Screen Carousel'''
{
 
   "id": "<TIMESTAMP>",
Req-Topic: tft/runtime/in<syntaxhighlight lang="json">
   "origin": "system-health",
{
   "id": "TIMESTAMP",
   "origin": "APP",
   "task": {
   "task": {
     "action": "SET_CAROUSEL",
     "action": "get_hw_info",
     "params": {
     "taskResult": {
       "startIndex": 0,
       "cpu": {......},
       "screens": [
       "ram": {......},
        {
      "emmc": {......},
          "type": "image",
      "block_devices": {......},
          "image": "default.jpg"
      "filesystems": {......},
        },
      "mmc_sysfs": {......},
        {
      "emmc_extcsd": {......}
          "type": "image",
          "image": "status.jpg"
        },
        {
          "type": "confirm",
          "question": "Do you want to continue?"
        }
      ]
     }
     }
   }
   }
}
}
 
</syntaxhighlight>
</syntaxhighlight>'''Parameters:'''
{| class="wikitable tech-table"
{| class="wikitable"
|-
|'''Field'''
|'''Section'''
|'''Description'''
|'''Description'''
|-
|-
|screens
|'''cpu'''
|Ordered list of screens
|CPU and board model information.
|-
|'''ram'''
|RAM total, used, and free memory.
|-
|'''emmc'''
|Filtered eMMC device and partition information.
|-
|'''block_devices'''
|Complete block device list from '''lsblk''', including eMMC, boot partitions, loop devices, zram, NVMe, USB storage, etc.
|-
|'''filesystems'''
|Mounted filesystem usage from '''df -h'''.
|-
|'''mmc_sysfs'''
|Low-level MMC/eMMC identity fields read from '''/sys/block/mmcblk*/device'''.
|-
|-
|Start  lndex
|'''emmc_extcsd'''
|Initial active screen (optional, default = 0)
|Parsed eMMC EXT_CSD information from '''mmc extcsd read''', including health, revision, RPMB, boot, and partitioning data.
|}
|}
'''Reply'''


Reply-Topic: '''tft/runtime/out''' <syntaxhighlight lang="json">
* '''CPU'''
 
The '''cpu''' object describes the detected board and CPU.<syntaxhighlight lang="json" line="1">
{
{
   "id": "TIMESTAMP",
   "board_model": "Raspberry Pi Compute Module 4 Rev 1.1",
   "origin": "tft",
   "cpu": {
  "task": {
    "architecture": "aarch64",
     "taskResult": {
    "op_modes": "32-bit, 64-bit",
       "success": true,
    "byte_order": "Little Endian",
       "activeIndex": 0,
    "vendor": "ARM",
       "totalScreens": 3
    "model_name": "Cortex-A72",
    "model": "3",
    "stepping": "r0p3",
    "cpu_count": 4,
    "online_cpus": "0-3",
    "threads_per_core": 1,
    "cores_per_cluster": 4,
    "clusters": 1,
     "frequency": {
       "scaling_percent": 60.0,
      "min_mhz": 600.0,
       "max_mhz": 1500.0,
       "bogomips": 108.0
     }
     }
   }
   }
}
}
</syntaxhighlight>
</syntaxhighlight>
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!'''Description'''
|-
|board_model
|string / null
|Hardware board model read from device-tree.
|-
|cpu.architecture
|string
|CPU architecture, for example '''aarch64'''.
|-
|cpu.op_modes
|string
|Supported CPU operation modes.
|-
|cpu.byte_order
|string
|CPU byte order.
|-
|cpu.vendor
|string
|CPU vendor.
|-
|cpu.model_name
|string
|CPU model name.
|-
|cpu.model
|string / number
|CPU model identifier.
|-
|cpu.stepping
|string
|CPU stepping/revision.
|-
|cpu.cpu_count
|number
|Number of detected CPU cores.
|-
|cpu.online_cpus
|string
|Online CPU list.
|-
|cpu.threads_per_core
|number
|Number of threads per core.
|-
|cpu.cores_per_cluster
|number
|Number of cores per cluster.
|-
|cpu.clusters
|number
|Number of CPU clusters.
|-
|cpu.frequency.scaling_percent
|number / null
|Current CPU frequency scaling percentage.
|-
|cpu.frequency.min_mhz
|number / null
|Minimum CPU frequency in MHz.
|-
|cpu.frequency.max_mhz
|number / null
|Maximum CPU frequency in MHz.
|-
|cpu.frequency.bogomips
|number / null
|BogoMIPS value reported by the system.
|}
* '''RAM'''


=== 30. Analoglnputs Actor ===
The '''ram''' object reports system memory usage.
 
{| class="wikitable tech-table"
==== 30.1 App Interfacing ====
!'''Field'''
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
!'''Type'''
 
!'''Description'''
===== 30.1.1 Configurations =====
|-
'''  Topic: analoglnputs/config/in - Set ADC channels configurations'''
|'''total'''
 
|string
'''mode'''
|Total system RAM.
 
|-
* continuous
|'''used'''
* single
|string
|Currently used RAM.
|-
|'''free'''
|string
|Currently free RAM.
|}


'''type'''
* '''EMMC'''


* voltage
The '''emmc''' object is a '''filtered eMMC''' '''view'''. It focuses on the main eMMC disk and its partitions.<syntaxhighlight lang="json" line="1">
* current
<syntaxhighlight lang="json">
{
{
   "id": "<TIMESTAMP>",
   "devices": [
  "origin": "APP",
    {
  "task": {
      "name": "mmcblk0",
    "taskParams": {
      "model": null,
       "AI1": {
      "serial": "0x121b491e",
        "mode": "single",
       "size": "29.1G",
        "type": "voltage"
      "type": "disk",
       },
      "transport": "mmc",
       "AI2": {
      "filesystem": null,
        "mode": "single",
       "mountpoints": [],
        "type": "voltage"
       "partitions": [
      },
        {
      "AI3": {
          "name": "mmcblk0p1",
        "mode": "single",
          "size": "512M",
        "type": "current"
          "type": "part",
      },
          "filesystem": "vfat",
      "AI4": {
          "mountpoints": [
        "mode": "single",
            "/boot/firmware"
        "type": "current"
          ]
       }
        },
        {
          "name": "mmcblk0p2",
          "size": "28.6G",
          "type": "part",
          "filesystem": "ext4",
          "mountpoints": [
            "/"
          ]
        }
       ]
     }
     }
   }
   ]
}
 
</syntaxhighlight>Reply-Topic: analoglnputs/config/out<syntaxhighlight lang="json">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AI1": {
        "success": true
      },
      "AI2": {
        "success": true
      },
      "AI3": {
        "success": true
      },
      "AI4": {
        "success": true
      }
    }
  }
}
}
</syntaxhighlight>'''Device fields'''
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!'''Description'''
|-
|devices[ ]
|array
|List of detected main eMMC devices.
|-
|devices[ ].serial
|string / null
|eMMC block device name, for example '''mmcblk0'''.
|-
|devices[ ].size
|string
|Device model, when available.
|-
|devices[ ].type
|string
|Device serial number.
|-
|devices[ ].transport
|string / null
|Device size.
|-
|devices[ ].filesystem
|string / null
|Device type, usually '''disk'''.
|-
|devices[ ].mountpoints
|array
|Transport type, usually '''mmc'''.
|-
|devices[ ].partitions
|array
|Filesystem directly on the disk. Usually null when partitions exist.
|-
|devices[ ].name
|string
|Mountpoints directly associated with the disk.
|-
|devices[ ].model
|string / null
|Partitions belonging to this eMMC disk.
|}
'''Partition fields'''
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!'''Description'''
|-
|name
|string
|Partition name, for example '''mmcblk0p1'''.
|-
|size
|string
|Partition size.
|-
|type
|string
|Partition type, usually '''part'''.
|-
|filesystem
|string / null
|Filesystem type, for example '''vfat''' or '''ext4'''.
|-
|mountpoints
|array
|Mountpoints for the partition.
|}


====== d) block_devices ======
The '''block_devices''' object is the complete storage/device tree returned by '''lsblk'''.<syntaxhighlight lang="json" line="1">
{
  "devices": [
    {
      "name": "mmcblk0",
      "model": null,
      "serial": "0x121b491e",
      "size": "29.1G",
      "type": "disk",
      "transport": "mmc",
      "filesystem": null,
      "mountpoints": [],
      "children": [
        {
          "name": "mmcblk0p1",
          "model": null,
          "serial": null,
          "size": "512M",
          "type": "part",
          "transport": "mmc",
          "filesystem": "vfat",
          "mountpoints": [
            "/boot/firmware"
          ],
          "children": []
        }
      ]
    }
  ],
  "stderr": ""
}
</syntaxhighlight>
</syntaxhighlight>
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!'''Description'''
|-
|devices
|array
|List of block devices.
|-
|stderr
|string
|Command error output, if any.
|-
|devices[index].name
|string
|Device name.
|-
|devices[index].model
|string / null
|Device model.
|-
|devices[index].serial
|string / null
|Device serial number.
|-
|devices[index].size
|string
|Device size.
|-
|devices[index].type
|string
|Device type, for example '''disk''' , '''part''' , or '''loop'''.
|-
|devices[index].transport
|string / null
|Transport type, for example '''mmc''' , '''nvme''' , or '''usb'''.
|-
|devices[index].filesystem
|string / null
|Filesystem type, for example '''ext4''' , '''vfat''' , or '''swap'''.
|-
|devices[index].mountpoints
|array
|List of mountpoints. Empty if not mounted.
|-
|devices[index].children
|array
|Child block devices, usually partitions.
|}


===== 30.1.2 Runtime Data =====
====== e) file_systems ======
'''Topic: analoglnputs/runtime/in.'''
The '''file_systems''' object reports mounted filesystem usage, equivalent to '''df -h'''.<syntaxhighlight lang="json" line="1">
 
action:
 
* READ
* PAUSE (only applicable in continuous mode)
* RESUME (only applicable in continuous mode)
<syntaxhighlight lang="json">
{
{
   "id": "<TIMESTAMP>",
   "filesystems": [
   "origin": "APP",
    {
   "task": {
      "source": "/dev/mmcblk0p2",
     "taskParams": {
      "filesystem": "ext4",
       "AI1": {
      "size": "29G",
        "action": "READ"
      "used": "5.8G",
       },
      "available": "23G",
       "AI2": {
      "use_percent": "21%",
         "action": "READ"
      "mountpoint": "/",
      },
      "parsed": true
      "AI3": {
    },
         "action": "READ"
    {
      },
      "source": "/dev/nvme0n1p1",
      "AI4": {
      "filesystem": "ext4",
         "action": "READ"
      "size": "234G",
      "used": "2.1M",
      "available": "222G",
      "use_percent": "1%",
      "mountpoint": "/mnt/nvme",
      "parsed": true
    }
  ],
  "stderr": ""
}
</syntaxhighlight>
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!'''Description'''
|-
|filesystems
|array
|List of mounted filesystems.
|-
|stderr
|string
|Command error output, if any.
|-
|filesystems[index].source
|string
|Filesystem source, for example '''/dev/mmcblk0p2''' , '''tmpfs''' , or '''udev'''.
|-
|filesystems[index].filesystem
|string
|Filesystem type, for example '''ext4''' , '''vfat''' , '''tmpfs''' , or '''devtmpfs'''.
|-
|filesystems[index].size
|string
|Total filesystem size.
|-
|filesystems[index].used
|string
|Used space.
|-
|filesystems[index].available
|string
|Available space.
|-
|filesystems[index].use_percent
|string
|Used percentage.
|-
|filesystems[index].mountpoint
|string
|Mount location.
|-
|filesystems[index].parsed
|boolean
|'''true''' if the parser successfully parsed this filesystem entry.
|}
 
====== f) mmc_sysfs ======
The '''mmc_sysfs''' object exposes low-level MMC/eMMC identity fields read from:
 
'''/sys/block/mmcblk*/device/'''
 
This is useful for production traceability, device identification and diagnostics.<syntaxhighlight lang="json" line="1">
{
   "source": "/sys/block",
   "fields": [
    "name",
    "cid",
    "csd",
    "date",
    "manfid",
    "oemid",
     "serial"
  ],
  "devices": [
    {
       "device": "mmcblk0",
      "base_path": "/sys/block/mmcblk0/device",
       "available": true,
       "fields": {
         "name": "BJTD4R",
        "cid": "150100424a5444345203121b491e7b00",
        "csd": "d02701320f5903fff6dbffef8e404000",
         "date": "07/2024",
        "manfid": "0x000015",
        "oemid": "0x0100",
         "serial": "0x121b491e"
       }
       }
     }
     }
   }
   ]
}
}
 
</syntaxhighlight>
</syntaxhighlight>Reply-Topic: analoglnputs/runtime/out<syntaxhighlight lang="json">
{| class="wikitable tech-table"
{
!'''Field'''
   "id": "<TIMESTAMP>",
!'''Type'''
   "origin": "APP",
!'''Description'''
   "task": {
|-
     "taskResult": {
|source
       "AI1": {
|string
        "success": true,
|Base sysfs source path.
        "value": <_FLOAT_>
|-
       },
|fields
       "AI2": {
|array
        "success": true,
|List of sysfs fields collected.
        "value": <_FLOAT_>
|-
       },
|devices
      "AI3": {
|array
        "success": true,
|List of detected MMC/eMMC devices.
        "value": <_FLOAT_>
|-
       },
|devices[index].device
       "AI4": {
|string
        "success": true,
|MMC block device name, for example '''mmcblk0'''.
        "value": <_FLOAT_>
|-
       }
|devices[index].base_path
|string
|Sysfs path used for this device.
|-
|devices[index].available
|boolean
|Indicates whether the sysfs path exists.
|-
|devices[index].fields.name
|string / null
|eMMC product name.
|-
|devices[index].fields.cid
|string / null
|Card Identification register.
|-
|devices[index].fields.csd
|string / null
|Card Specific Data register.
|-
|devices[index].fields.date
|string / null
|Manufacturing date.
|-
|devices[index].fields.manfid
|string / null
|Manufacturer ID.
|-
|devices[index].fields.oemid
|string / null
|OEM/application ID.
|-
|devices[index].fields.serial
|string / null
|eMMC serial number.
|}
 
====== e) emmc_extcsd ======
The '''emmc_extcsd''' object contains parsed information from:
 
'''mmc extcsd read /dev/mmcblk0'''
{| class="wikitable tech-table"
!'''Category'''
!'''Description'''
|-
|revision
|EXT_CSD and MMC version.
|-
|health
|eMMC lifetime and pre-EOL state.
|-
|boot
|Boot partition/protection configuration.
|-
|rpmb
|Replay Protected Memory Block information.
|-
|sector
|Sector count and capacity information, when available.
|-
|partitioning
|Partitioning and enhanced-area information.
|}
'''emmc_extcsd.devices[''' '''].revision'''<syntaxhighlight lang="json" line="1">
{
   "ext_csd_revision": "1.8",
   "mmc_version": "MMC 5.1"
}
</syntaxhighlight>
{| class="wikitable tech-table"
!'''Field'''
!Type
!'''Description'''
|-
|ext_csd_revision
|string
|EXT_CSD revision.
|-
|mmc_version
|string
|MMC/eMMC standard version.
|}
'''emmc_extcsd.devices[ ].health'''<syntaxhighlight lang="json" line="1">
{
   "life_time_estimation_a": {
     "field": {
       "register": "DEVICE_LIFE_TIME_EST_TYP_A",
      "index": null,
      "description": "eMMC Life Time Estimation A",
      "value": "0x01",
      "value_int": 1,
       "value_hex": "0x1"
    },
    "decoded": {
       "state": "normal",
      "used_percent_min": 0,
      "used_percent_max": 10
    }
  },
  "life_time_estimation_b": {
    "field": {
      "register": "DEVICE_LIFE_TIME_EST_TYP_B",
      "index": null,
      "description": "eMMC Life Time Estimation B",
      "value": "0x01",
      "value_int": 1,
       "value_hex": "0x1"
    },
    "decoded": {
      "state": "normal",
      "used_percent_min": 0,
       "used_percent_max": 10
    }
  },
  "pre_eol": {
    "field": {
       "register": "PRE_EOL_INFO",
      "index": null,
      "description": "eMMC Pre EOL information",
      "value": "0x01",
      "value_int": 1,
       "value_hex": "0x1"
    },
    "decoded": {
      "state": "normal"
     }
     }
   }
   }
}
}
</syntaxhighlight>
</syntaxhighlight>
 
{| class="wikitable tech-table"
=== 31. Analog Outputs Actor ===
!'''Field'''
 
!'''Description'''
==== 31.1 App Interfacing ====
|-
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
|life_time_estimation_a
 
|Wear estimation for eMMC memory type A.
===== 31.1.1 Set analog outputs signal =====
|-
Req-Topic: analogOutputs/config/in
|life_time_estimation_b
 
|Wear estimation for eMMC memory type B.
'''Output:''' current within 0-20 mA
|-
 
|pre_eol
'''mode:''' on/off<syntaxhighlight lang="json">
|Pre-end-of-life state.
|}
Lifetime Decoding
{| class="wikitable tech-table"
!'''Raw Value'''
!'''Decoded State'''
!Meaning
|-
|0x00
|not_defined
|Not defined by device.
|-
|0x01
|normal
|0% to 10% estimated lifetime used.
|-
|0x02
|normal
|10% to 20% estimated lifetime used.
|-
|0x03
|normal
|20% to 30% estimated lifetime used.
|-
|0x04
|normal
|30% to 40% estimated lifetime used.
|-
|0x05
|normal
|40% to 50% estimated lifetime used.
|-
|0x06
|normal
|50% to 60% estimated lifetime used
|-
|0x07
|normal
|60% to 70% estimated lifetime used.
|-
|0x08
|normal
|70% to 80% estimated lifetime used.
|-
|0x09
|normal
|80% to 90% estimated lifetime used.
|-
|0x0A
|normal
|90% to 100% estimated lifetime used.
|-
|0x0B
|exceeded
|Estimated maximum lifetime exceeded.
|}
Pre-EOL Decoding
{| class="wikitable tech-table"
!'''Raw Value'''
!'''Decoded State'''
!Meaning
|-
|0x00
|not_defined
|Not defined.
|-
|0x01
|normal
|Normal condition.
|-
|0x02
|warning
|Warning state. Monitor or plan replacement.
|-
|0x03
|urgent
|Urgent state. Replacement recommended.
|}
'''emmc_extcsd.devices[ ].boot'''<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "partition_config": {
   "origin": "APP",
    "field": null,
   "task": {
    "decoded": null
     "taskParams": {
  },
       "mode": "on",
  "boot_config_protection": null,
       "AO1": {
  "boot_bus_conditions": null,
        "current": <_FLOAT_>
  "boot_write_protection": {
       },
    "register": "BOOT_WP",
       "AO2": {
    "index": null,
        "current": <_FLOAT_>
    "description": "Boot Area Write protection",
       }
    "value": "0x00",
    "value_int": 0,
    "value_hex": "0x0"
  },
   "boot_size": {
    "field": null,
    "decoded": null
  }
}
</syntaxhighlight>
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!Description
|-
|partition_config
|object / null
|Boot partition configuration, if available.
|-
|boot_config_protection
|object / null
|Boot configuration protection status.
|-
|boot_bus_conditions
|object / null
|Boot bus width/mode conditions.
|-
|boot_write_protection
|object / null
|Boot area write protection status.
|-
|boot_size
|object / null
|Boot partition size, if available.
|}
'''emmc_extcsd.devices[ ].rpmb'''
 
RPMB means '''Replay Protected Memory Block'''. It is a protected eMMC area often used for secure storage.<syntaxhighlight lang="json" line="1">
{
   "size": {
     "field": {
       "register": "RPMB_SIZE_MULT",
      "index": null,
      "description": "RPMB Size",
      "value": "0x20",
       "value_int": 32,
      "value_hex": "0x20"
    },
    "decoded": {
      "bytes": 4194304,
      "kb": 4194.3,
      "mb": 4.19,
       "gb": 0.0,
       "kib": 4096.0,
      "mib": 4.0,
       "gib": 0.0
     }
     }
   }
   }
}
}
 
</syntaxhighlight>
</syntaxhighlight>Reply-Topic: analogOutputs/config/out<syntaxhighlight lang="json">
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!Description
|-
|size.field
|object / null
|Raw RPMB size register information.
|-
|size.decoded.bytes
|number
|RPMB size in bytes.
|-
|size.decoded.kb
|number
|RPMB size in decimal KB.
|-
|size.decoded.mb
|number
|RPMB size in decimal MB.
|-
|size.decoded.gb
|number
|RPMB size in decimal GB.
|-
|size.decoded.kib
|number
|RPMB size in KiB.
|-
|size.decoded.mib
|number
|RPMB size in MiB.
|-
|size.decoded.gib
|number
|RPMB size in GiB.
|}
'''emmc_extcsd.devices[ ].sector'''<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "sector_count": null,
   "origin": "APP",
  "sector_size_bytes": 512,
   "task": {
  "user_capacity": null
     "taskResult": {
}
      "mode": "on",
</syntaxhighlight>
      "AO1": {
{| class="wikitable tech-table"
        "success": true,
!'''Field'''
        "current": <_FLOAT_>
!'''Type'''
      },
!Description
      "AO2": {
|-
        "success": true,
|sector_count
        "current": <_FLOAT_>
|object / null
      }
|Parsed sector count register, if available.
     }
|-
|sector_size_bytes
|number
|Sector size used for capacity calculation.
|-
|user_capacity
|object / null
|Calculated user capacity, if sector count is available.
|}
'''emmc_extcsd.devices[ ].partitioning'''<syntaxhighlight lang="json" line="1">
{
   "partitioning_support": {
    "register": "PARTITIONING_SUPPORT",
    "index": null,
    "description": "Partitioning Support",
    "value": "0x07",
    "value_int": 7,
    "value_hex": "0x7"
  },
   "partition_setting_completed": {
     "register": "PARTITION_SETTING_COMPLETED",
    "index": null,
    "description": "Partitioning Setting",
    "value": "0x00",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "partition_attribute": {
    "register": "PARTITIONS_ATTRIBUTE",
    "index": null,
    "description": "Partitions attribute",
    "value": "0x00",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "max_enhanced_area_size": {
    "register": "MAX_ENH_SIZE_MULT",
    "index": null,
    "description": "Max Enhanced Area Size",
    "value": "0x000747",
    "value_int": 1863,
    "value_hex": "0x747"
  },
  "enhanced_user_area_start": {
    "register": "ENH_START_ADDR",
    "index": null,
    "description": "Enhanced User Data Start Address",
    "value": "0x00000000",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "enhanced_user_area_size": {
     "register": "ENH_SIZE_MULT",
    "index": null,
    "description": "Enhanced User Data Area Size",
    "value": "0x000000",
    "value_int": 0,
    "value_hex": "0x0"
   }
   }
}
}
</syntaxhighlight>
</syntaxhighlight>
{| class="wikitable tech-table"
!'''Field'''
!'''Type'''
!Description
|-
|partitioning_support
|object / null
|Supported partitioning features.
|-
|partition_setting_completed
|object / null
|Indicates whether partition settings were finalized.
|-
|user_capacity
|object / null
|Partition attribute register.
|-
|max_enhanced_area_size
|object / null
|Maximum enhanced area size multiplier.
|-
|enhanced_user_area_start
|object / null
|Enhanced user data area start address.
|-
|enhanced_user_area_size
|object / null
|Enhanced user data area size.
|}
==== <big>24.4 TempSensor Actor</big> ====


===== 31.1.2 Set analog outputs =====
===== 24.4.1 App Interfacing =====
Req-Topic: analogOutputs/runtime/in
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.


'''current:''' current within 0-20 mA<syntaxhighlight lang="json">
====== a) Set temperature sensor configurations ======
Req-Topic: tempSensor/config/in
 
ALERT:
 
* activate: true(active)/false
* templow: alert temperature lower limit
* tempHigh: alert temperature upper limit
<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 1,642: Line 3,049:
   "task": {
   "task": {
     "taskParams": {
     "taskParams": {
       "AO1": {
       "ALERT": {
         "action": "SET",
         "activate": true,
        "current": <_FLOAT_>
         "tempLow": 0,
      },
         "tempHigh": 80
      "AO2": {
         "action": "SET",
         "current": <_FLOAT_>
       }
       }
     }
     }
   }
   }
}
}
 
</syntaxhighlight>Reply-Topic: tempSensor/config/out<syntaxhighlight lang="json" line="1">
</syntaxhighlight>Reply-Topic: analoigOutputs/runtime/out<syntaxhighlight lang="json">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 1,660: Line 3,063:
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "AO1": {
       "success": true,
        "success": true,
      "ALERT": {
        "current": <_FLOAT_>
        "activate": true,
      },
         "tempLow": 0,
      "AO2": {
         "tempHigh": 80
         "success": true,
         "current": <_FLOAT_>
       }
       }
     }
     }
Line 1,674: Line 3,075:
</syntaxhighlight>
</syntaxhighlight>


===== 31.1.3 Read analog outputs settings =====
====== b) Read temperature sensor configurations ======
Req-Topic: analogOutputs/runtime/in
Req-Topic: tempSensor/config/in
 
ALERT:
 
* activate: true(active)/false
 
LIMITS:


'''current''': current within 0-20 mA<syntaxhighlight lang="json">
* templow: alert temperature lower limit
* tempHigh: alert temperature upper limit
<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
   "origin": "APP",
   "origin": "APP",
   "task": {
   "task": {
     "taskParams": {
     "action": "READ"
      "AO1": {
        "action": "READ"
      },
      "AO2": {
        "action": "READ"
      }
    }
   }
   }
}
}


</syntaxhighlight>Reply-Topic: analogOutputs/runtime/out<syntaxhighlight lang="json">
</syntaxhighlight>Reply-Topic: tempSensor/config/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 1,699: Line 3,101:
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "AO1": {
       "success": true,
        "success": true,
      "ALERT": {
        "current": <_FLOAT_>
        "activate": true,
      },
         "tempLow": 0,
      "AO2": {
         "tempHigh": 80
         "success": true,
         "current": <_FLOAT_>
       }
       }
     }
     }
Line 1,713: Line 3,113:
</syntaxhighlight>
</syntaxhighlight>


=== 32. Digital lnputs Actor ===
====== c) Read temperature and alert status ======
* unit: Temperature unit of measure
* alert: true (triggered) or false


==== 32.1 App Interfacing ====
Req-Topic: tempSensor/runtime/in<syntaxhighlight lang="json" line="1">
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credentials.
 
===== 32.1.1 Set digital input pin/pins speed fast/slow =====
The '''fast''' speed setting supports edge detection speed up to 100 Hz and the '''slow''' speed settings supports up to 10 Hz.
 
'''Fast Mode''' generates a message on every I/O state change, which may result in a '''high message payload''' during operation. Fast Mode should therefore only be enabled when '''strictly required'''.
 
Req-Topic: digitallnputs/config/in<syntaxhighlight lang="json">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
   "origin": "APP",
   "origin": "APP",
   "task": {
   "task": {
     "taskParams": {
     "action": "READ"
      "DI1": {
        "speed": "fast"
      },
      "DI2": {
        "speed": "slow"
      },
      "DI3": {
        "speed": "fast"
      },
      "DI4": {
        "speed": "fast"
      }
    }
   }
   }
}
}
</syntaxhighlight>Reply-Topic: digitallnputs/config/out<syntaxhighlight lang="json">
 
</syntaxhighlight>Reply-Topic: tempSensor/runtime/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
Line 1,750: Line 3,132:
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "DI1": {
       "success": true,
        "success": true,
       "data": {
        "speed": "fast"
         "temperature": <_FLOAT_>,
      },
         "unit": "C",
       "DI2": {
         "alert": true
         "success": true,
         "speed": "slow"
      },
      "DI3": {
         "success": true,
        "speed": "fast"
      },
      "DI4": {
        "success": true,
        "speed": "fast"
       }
       }
     }
     }
   }
   }
}
}
</syntaxhighlight>
</syntaxhighlight>


===== 32.1.2 Get all digital input pins state =====
==== <big>24.5 TFT Actor</big> ====
 
===== 24.5.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to control and interact with the TFT display, or frontal panel LCD screen. Connecting to the broker for this Area requires no credentials.


Req-Topic: digitallnputs/runtime/in<syntaxhighlight lang="json">
===== 24.5.2 TFT Display Actor =====
{
  The TFT Actor is responsible for:
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}


</syntaxhighlight>Reply-Topic: digitallnputs/runtime/out
* Rendering static and informative screens on the TFT display
* Reacting to joystick input (LEFT/ RIGHT/ CENTER/ UP/ DOWN)
* Managing screen navigation and user confirmation flows
* Providing feedback to the application via MQTT


state: high/low<syntaxhighlight lang="json">
====== a) Screen Carousel Concept ======
{
The TFT actor maintains an '''ordered list of screens''' (carousel).
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DI1": {
        "success": true,
        "state": "high"
      },
      "DI2": {
        "success": true,
        "state": "low"
      },
      "DI3": {
        "success": true,
        "state": "high"
      },
      "DI4": {
        "success": true,
        "state": "low"
      }
    }
  }
}


</syntaxhighlight>
* Screens are navigated using the joystick:


=== 33. Digital Outputs Actor ===
- LEFT --> Previous screen


==== 33.1 App Interfacing ====
- RIGHT --> Next screen
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this area requires no credencials.


===== 33.1.1 Get all digital output pins state =====
* The carousel wraps around:


Req-Topic: digitalOutputs/runtime/in<syntaxhighlight lang="json">
- LEFT on first screen --> last screen
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }


</syntaxhighlight>Reply-Topic: digitalOutputs/runtime/out<syntaxhighlight lang="json">
- RIGHT on last screen --> first screen
{
 
  "id": "<TIMESTAMP>",
====== b) Screen Types ======
  "origin": "APP",
The TFT actor supports the following screen types:
  "task": {
 
    "taskResult": {
'''Image Screen'''
      "DO1": {
 
        "success": true,
* Displays a static JPEG image
        "state": "low"
* Default screen shown at boot
      },
* No user interaction required
      "DO2": {
 
        "success": true,
'''Network Information Screen'''
        "state": "high"
 
      },
* Display a interface with information about the networks of the device
      "DO3": {
* Updated on load
        "success": true,
* No user interaction required
        "state": "high"
 
      },
====== c) Joystick Navigation Logic ======
      "DO4": {
'''Carousel Navigation:'''
        "success": true,
{| class="wikitable"
        "state": "low"
|'''Joystick  Input'''
      },
|'''Action'''
      "DO5": {
|-
        "success": true,
|LEFT
        "state": "low"
|Previous screen
      },
|-
      "DO6": {
|RIGHT
        "success": true,
|Next screen
        "state": "low"
|-
      },
|DOWN
      "DO7": {
|Refresh current screen
        "success": true,
|}
        "state": "low"
 
      },
====== d) Boot Behavior ======
      "DO8": {
At system boot:
        "success": true,
 
        "state": "low"
# TFT actor initializes the display
      }
# Last available carousel is loaded
    }
# First screen is rendered
  }
# Joystick subscriptions are activated
}
# Actor waits for runtime commands
</syntaxhighlight>
 
====== e) Design Notes & Constraints ======
* TFT actor does not expose joystick state
* Joystick actor remains independent
* TFT actor internally consumes joystick events
* Carousel state is local to the TFT actor
* Screen rendering is synchronous; input handling is asynchronous
* Confirmation screens always require explicit CENTER press
 
===== 24.5.3 User interaction through MQTT =====
Enabling interaction with the carousel using the topic tft/runtime/in . Actions available will be public to the user.
 
'''Runtime commands'''


===== 33.1.2 Set all digital output pins state =====
'''Go to screen'''


Req-Topic: digitalOutputs/runtime/in<syntaxhighlight lang="json">
Req-Topic: tft/runtime/in<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
   "origin": "APP",
   "origin": "APP",
   "task": {
   "task": {
     "taskParams": {
     "action": "SET_CAROUSEL",
      "DO1": {
    "params": {
        "action": "SET",
       "index": 2
        "state": "low"
     }
      },
      "DO2": {
        "action": "SET",
        "state": "high"
      },
      "DO3": {
        "action": "SET",
        "state": "high"
      },
      "DO4": {
        "action": "SET",
        "state": "low"
      },
      "DO5": {
        "action": "SET",
        "state": "low"
      },
      "DO6": {
        "action": "SET",
        "state": "low"
      },
      "DO7": {
        "action": "SET",
        "state": "low"
      },
       "DO8": {
        "action": "SET",
        "state": "low"
      }
     }
   }
   }
}
}
</syntaxhighlight>Reply-Topic: digitalOutputs/runtime/out<syntaxhighlight lang="json">
 
</syntaxhighlight>Reply-Topic: tft/runtime/out<syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "<TIMESTAMP>",
  "origin": "tft",
  "task": {
    "taskResult": {
      "success": true,
      "index": 2
    }
  }
}
</syntaxhighlight>'''Set TFT Screen Carousel'''
Req-Topic: tft/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "TIMESTAMP",
   "origin": "APP",
   "origin": "APP",
   "task": {
   "task": {
     "taskResult": {
     "action": "SET_CAROUSEL",
      "D01": {
    "params": {
        "success": true,
       "startIndex": 0,
        "state": "low"
       "screens": [
       },
         {
      "D02": {
          "type": "image",
        "success": true,
          "image": "default.jpg"
        "state": "high"
         },
      },
        {
       "D03": {
          "type": "image",
         "success": true,
          "image": "status.jpg"
        "state": "high"
         },
      },
        {
      "D04": {
          "type": "confirm",
        "success": true,
          "question": "Do you want to continue?"
         "state": "high"
         }
      },
       ]
      "D05": {
        "success": true,
        "state": "high"
      },
      "D06": {
        "success": true,
         "state": "low"
      },
      "D07": {
        "success": true,
        "state": "low"
      },
      "D08": {
        "success": true,
         "state": "low"
       }
     }
     }
   }
   }
}  
}


</syntaxhighlight>
</syntaxhighlight>'''Parameters:'''
 
{| class="wikitable"
==== 33.2 Notes ====
|'''Field'''
If the busi2c-3 is not powered, we will get this:
|'''Description'''
|-
|screens
|Ordered list of screens
|-
|Start  lndex
|Initial active screen (optional, default = 0)
|}
'''Reply'''


Topic: '''digit a lOutputs/runtime/ out''' <syntaxhighlight lang="json">
Reply-Topic: '''tft/runtime/out''' <syntaxhighlight lang="json" line="1">
{
{
   "id": "<TIMESTAMP>",
   "id": "TIMESTAMP",
   "origin": "APP",
   "origin": "tft",
   "task": {
   "task": {
     "taskResult": {
     "taskResult": {
       "DO1": {
       "success": true,
        "success": false,
      "activeIndex": 0,
        "state": "DO_not_powered"
      "totalScreens": 3
      },
    }
       "DO2": {
  }
         "success": false,
}
         "state": "DO_not_powered"
 
</syntaxhighlight>
 
==== <big>24.6 AnalogInputs Actor</big> ====
 
===== 24.6.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
 
====== a) Configurations ======
'''  Topic: analogInputs/config/in - Set ADC channels configurations'''
 
'''mode'''
 
* continuous
* single
 
'''type'''
 
* voltage
* current
<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
       "AI1": {
         "mode": "single",
         "type": "voltage"
       },
       },
       "DO3": {
       "AI2": {
         "success": false,
         "mode": "single",
         "state": "DO_not_powered"
         "type": "voltage"
       },
       },
       "DO4": {
       "AI3": {
         "success": false,
         "mode": "single",
         "state": "DO_not_powered"
         "type": "current"
       },
       },
       "DO5": {
       "AI4": {
         "success": false,
         "mode": "single",
         "state": "DO_not_powered"
         "type": "current"
      }
    }
  }
}
 
</syntaxhighlight>Reply-Topic: analogInputs/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AI1": {
        "success": true
       },
       },
       "DO6": {
       "AI2": {
         "success": false,
         "success": true
        "state": "DO_not_powered"
       },
       },
       "DO7": {
       "AI3": {
         "success": false,
         "success": true
         "state": "DO_not_powered"
      },
      "AI4": {
        "success": true
      }
    }
  }
}
 
</syntaxhighlight>
 
====== b) Runtime Data ======
'''Topic: analogInputs/runtime/in.'''
 
action:
 
* READ
* PAUSE (only applicable in continuous mode)
* RESUME (only applicable in continuous mode)
<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AI1": {
        "action": "READ"
      },
      "AI2": {
        "action": "READ"
      },
      "AI3": {
         "action": "READ"
       },
       },
       "DO8": {
      "AI4": {
         "success": false,
        "action": "READ"
      }
    }
  }
}
 
</syntaxhighlight>Reply-Topic: analogInputs/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AI1": {
        "success": true,
        "value": <_FLOAT_>
      },
      "AI2": {
        "success": true,
        "value": <_FLOAT_>
      },
      "AI3": {
        "success": true,
        "value": <_FLOAT_>
      },
      "AI4": {
        "success": true,
        "value": <_FLOAT_>
      }
    }
  }
}
 
</syntaxhighlight>
 
===== 24.6.2 Usage Examples =====
 
==== <big>24.7 Analog Outputs Actor</big> ====
 
===== 24.7.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
 
====== a) Set analog outputs signal ======
Req-Topic: analogOutputs/config/in
 
'''Output:''' current within 0-20 mA
 
'''mode:''' on/off<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "mode": "on",
      "AO1": {
        "current": <_FLOAT_>
      },
      "AO2": {
        "current": <_FLOAT_>
      }
    }
  }
}
 
</syntaxhighlight>Reply-Topic: analogOutputs/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "mode": "on",
      "AO1": {
        "success": true,
        "current": <_FLOAT_>
      },
      "AO2": {
        "success": true,
        "current": <_FLOAT_>
      }
    }
  }
}
 
</syntaxhighlight>
 
====== b) Set analog outputs ======
Req-Topic: analogOutputs/runtime/in
 
'''current:''' current within 0-20 mA<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AO1": {
        "action": "SET",
        "current": <_FLOAT_>
      },
      "AO2": {
        "action": "SET",
        "current": <_FLOAT_>
      }
    }
  }
}
 
</syntaxhighlight>Reply-Topic: analoigOutputs/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AO1": {
        "success": true,
        "current": <_FLOAT_>
      },
      "AO2": {
        "success": true,
        "current": <_FLOAT_>
      }
    }
  }
}
 
</syntaxhighlight>
 
====== c) Read analog outputs settings ======
Req-Topic: analogOutputs/runtime/in
 
'''current''': current within 0-20 mA<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AO1": {
        "action": "READ"
      },
      "AO2": {
        "action": "READ"
      }
    }
  }
}
 
</syntaxhighlight>Reply-Topic: analogOutputs/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AO1": {
        "success": true,
        "current": <_FLOAT_>
      },
      "AO2": {
        "success": true,
        "current": <_FLOAT_>
      }
    }
  }
}
 
</syntaxhighlight>
 
==== <big>24.8 Digital Inputs Actor</big> ====
 
===== 24.8.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credentials.
 
====== a) Set digital input pin/pins speed fast/slow ======
The '''fast''' speed setting supports edge detection speed up to 100 Hz and the '''slow''' speed settings supports up to 10 Hz.
 
'''Fast Mode''' generates a message on every I/O state change, which may result in a '''high message payload''' during operation. Fast Mode should therefore only be enabled when '''strictly required'''.
 
Req-Topic: digitalInputs/config/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "DI1": {
        "speed": "fast"
      },
      "DI2": {
        "speed": "slow"
      },
      "DI3": {
        "speed": "fast"
      },
      "DI4": {
        "speed": "fast"
      }
    }
  }
}
</syntaxhighlight>Reply-Topic: digitalInputs/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DI1": {
        "success": true,
        "speed": "fast"
      },
      "DI2": {
        "success": true,
        "speed": "slow"
      },
      "DI3": {
        "success": true,
        "speed": "fast"
      },
      "DI4": {
        "success": true,
        "speed": "fast"
      }
    }
  }
}
</syntaxhighlight>
 
====== b) Get all digital input pins state ======
 
 
Req-Topic: digitalInputs/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}
 
</syntaxhighlight>Reply-Topic: digitalInputs/runtime/out
 
state: high/low<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DI1": {
        "success": true,
        "state": "high"
      },
      "DI2": {
        "success": true,
        "state": "low"
      },
      "DI3": {
        "success": true,
        "state": "high"
      },
      "DI4": {
        "success": true,
        "state": "low"
      }
    }
  }
}
 
</syntaxhighlight>
 
==== <big>24.9 Digital Outputs Actor</big> ====
 
===== 24.9.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this area requires no credencials.
 
====== a) Get all digital output pins state ======
 
 
Req-Topic: digitalOutputs/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
 
</syntaxhighlight>Reply-Topic: digitalOutputs/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DO1": {
        "success": true,
        "state": "low"
      },
      "DO2": {
        "success": true,
        "state": "high"
      },
      "DO3": {
        "success": true,
        "state": "high"
      },
      "DO4": {
        "success": true,
        "state": "low"
      },
      "DO5": {
        "success": true,
        "state": "low"
      },
      "DO6": {
        "success": true,
        "state": "low"
      },
      "DO7": {
        "success": true,
        "state": "low"
      },
       "DO8": {
        "success": true,
        "state": "low"
      }
    }
  }
}
</syntaxhighlight>
 
====== b) Set all digital output pins state ======
 
 
Req-Topic: digitalOutputs/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "DO1": {
        "action": "SET",
        "state": "low"
      },
      "DO2": {
        "action": "SET",
        "state": "high"
      },
      "DO3": {
        "action": "SET",
        "state": "high"
      },
      "DO4": {
        "action": "SET",
        "state": "low"
      },
      "DO5": {
        "action": "SET",
        "state": "low"
      },
      "DO6": {
        "action": "SET",
        "state": "low"
      },
      "DO7": {
        "action": "SET",
        "state": "low"
      },
      "DO8": {
        "action": "SET",
        "state": "low"
      }
    }
  }
}
</syntaxhighlight>Reply-Topic: digitalOutputs/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "D01": {
        "success": true,
        "state": "low"
      },
      "D02": {
        "success": true,
        "state": "high"
      },
      "D03": {
        "success": true,
        "state": "high"
      },
      "D04": {
        "success": true,
        "state": "high"
      },
      "D05": {
        "success": true,
        "state": "high"
      },
      "D06": {
        "success": true,
        "state": "low"
      },
      "D07": {
        "success": true,
        "state": "low"
      },
      "D08": {
        "success": true,
        "state": "low"
      }
    }
  }
}
 
</syntaxhighlight>
 
===== 24.9.2 Notes =====
If the busi2c-3 is not powered, we will get this:
 
Topic: '''digit a lOutputs/runtime/ out''' <syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DO1": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO2": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO3": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO4": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO5": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO6": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO7": {
         "success": false,
         "state": "DO_not_powered"
         "state": "DO_not_powered"
       }
       },
     }
      "DO8": {
   }
        "success": false,
}
        "state": "DO_not_powered"
      }
    }
  }
}
 
</syntaxhighlight>
 
==== <big>24.10 Joystick Actor</big> ====
 
===== 24.10.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
 
====== a) Get all joystick pins state ======
 
 
Req-Topic: joystick/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
 
</syntaxhighlight>Reply-Topic: joystick//runtime/out
 
state: pressed/released<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "JLEFT": {
        "success": true,
        "state": "pressed"
      },
      "JRIGHT": {
        "success": true,
        "state": "released"
      },
      "JUP": {
        "success": true,
        "state": "released"
      },
      "JDOWN": {
        "success": true,
        "state": "released"
      },
      "JCENTER": {
        "success": true,
        "state": "released"
      }
    }
  }
}
 
</syntaxhighlight>
 
==== <big>24.11 Buzzer Actor</big> ====
 
===== 24.11.1 Overview =====
The '''Buzzer Actor''' is responsible for controlling the onboard buzzer through MQTT commands. It receives runtime commands on an MQTT input topic, validates the requested buzzer operation, drives the buzzerthrough GPIO using '''libgpiod''', and publishes status/final responses on an MQTT output topic.
 
The actor currently controls '''GPIO line 25''' on '''/dev/gpiochip0''', with '''ACTIVE_LOW = False'''. It creates a
 
'''GpiodBuzzerDriver''' instance and routes incoming MQTT actions to runtime handlers.
 
The supported runtime actions are:
{| class="wikitable"
|'''Action'''
|'''Description'''
|-
|BEEP
|Plays a finite beep sequence, an infinite beep sequence, or a continuous tone
|-
|STOP
|Stops the currently active buzzer playback
|}
 
===== 24.11.2 MQTT Topics =====
{| class="wikitable"
|'''Topic'''
|'''Direction'''
|'''Description'''
|-
|buzzer/runtime/in
|Input
|Receives buzzer commands
|-
|buzzer/runtime/out
|Output
|Publishes status messages and final command responses
|}
The actor subscribes to '''buzzer/runtime/in''' and publishes all status/final replies to '''buzzer/runtime/out'''.
 
===== 24.11.3 Hardware and Datasheet Notes =====
The buzzer used is the '''MLT-8530 electro-magnetic SMD buzzer.'''
 
According to the datasheet:
{| class="wikitable"
|'''Parameter'''
|'''Value'''
|-
|Rated voltage
|3.6 Vo-p
|-
|Operating voltage
|2.5 ~ 4.5 Vo-p
|-
|Rated current
|Max. 95 mA
|-
|Rated test frequency
|2700 Hz
|-
|Duty cycle
|50% square wave
|-
|Sound output
|Min. 80 dB at 10 cm
|-
|Coil resistance
|16 ± 3 Ω
|-
|Resonant frequency
|2700 Hz
|}
 
===== 24.11.4 BEEP =====
The BEEP action supports two modes:
{| class="wikitable"
|'''Mode'''
|'''Description'''
|-
|sequence
|Plays one or more beeps with gaps between them
|-
|continuous
|Plays one continuous tone until '''STOP''' is received
|}
If no mode is provided, the default mode is: '''sequence'''
 
All messages should be sent to the topic '''buzzer/runtime/in'''
 
====== a) Default Datasheet-Aligned Beep ======
<syntaxhighlight lang="json" line="1">
{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
  "action": "BEEP"
  }
}
 
</syntaxhighlight>
 
====== b) N Beeps ======
Play '''<BEEPS_QUANTITY>''' beeps at '''<FREQUENCY>''' Hz. Each beep lasts '''<BEEP_DURATION>''' seconds, with
 
'''<GAP_BETWEEN_BEEPS>''' seconds of silence between beeps.<syntaxhighlight lang="json" line="1">{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
  "action": "BEEP",
  "params": {
      "frequency_hz": <FREQUENCY>,
      "duration_s": <BEEP_DURATION>,
      "count": <BEEPS_QUANTITY>,
      "gap_s": <GAP_BETWEEN_BEEPS>
    }
  }
}</syntaxhighlight>If you want to play repeated beeps forever until a '''STOP''' command arrives then you only need to pass the '''count: 0'''
 
====== c) Continuous Tone ======
Play one continuous <FREQUENCY> Hz tone until '''STOP'''.<syntaxhighlight lang="json" line="1">
{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
  "action": "BEEP",
  "params": {
      "mode": "continuous",
      "frequency_hz": <FREQUENCY>
    }
  }
}
</syntaxhighlight>If '''frequency_hz''' is omitted, the handler uses the configured default frequency.
 
====== d) Stop Buzzer ======
If you want to stop the beep sequence, just send this payload to the '''buzzer/runtime/in'''<syntaxhighlight lang="json" line="1">
{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
  "action": "STOP",
  }
}
</syntaxhighlight>
 
====== e) Buzzer payload parameters table ======
{| class="wikitable"
!Field
!Required
!Type
!Default
!Applies to
!Description
|-
|task
|Yes
|object
| -
|All requests
|Main task object. Contains the requested action and
optional parameters.
|-
|task.action
|Yes
|string
| -
|All requests
|Action to execute. Supported values: "BEEP" and
"STOP".
|-
|task.params
|No
|object
|{}
|BEEP
|Optional parameters for configuring the buzzer
behavior. Not needed for STOP.
|-
|task.params.mode
|No
|string
|"sequence"
|BEEP
|Playback mode. Supported values: "sequence" and
"continuous".
|-
|task.params.frequency_hz
|No
|number
|2700.0
|BEEP
|Buzzer frequency in Hz. Recommended/default value
is 2700 Hz , matching the buzzer resonant frequency.
|-
|task.params.duration_s
|No
|number
|0.2
|BEEP with
mode="sequence"
|Duration of each beep, in seconds.
|-
|task.params.count
|No
|integer
|1
|BEEP with
mode="sequence"
|Number of beeps to play. 0 means repeat forever
until STOP.
|-
|task.params.gap_s
|No
|number
|0.15
|BEEP with
mode="sequence"
|Silence gap between beeps, in seconds.
|-
|task.params.mode ="continuous"
|No
|string
| -
|BEEP
|Plays one continuous tone until STOP . In this mode,
duration_s , count , and gap_s are ignored.
|}
 
===== 24.11.5 Buzzer - diagram =====
[[File:Buzzer - diagram.svg|center|frameless|901x901px]]
 
===== 24.11.6 Buzzer Command timing charts - Examples =====
The following charts represent the command-level buzzer state over time.
 
They do not show the internal 2700 Hz switching frequency.
 
Instead, they show when the buzzer is logically:
{| class="wikitable"
|'''State'''
|'''Meaning'''
|-
|1
|Buzzer active / sound ON
|-
|0
|Buzzer inactive / silence
|}
 
====== a) Default BEEP command ======
<syntaxhighlight lang="json" line="1">
{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
  "action": "BEEP",
  }
}
</syntaxhighlight>Default values used:
{| class="wikitable"
|'''Parameter'''
|'''Value'''
|-
|duration_s
|0.2 s
|-
|count
|1
|-
|gap_s
|0.15 s
|}
'''Buzzer State'''
 
[[File:Default_Beep.svg|frameless]]
 
duration_s = 0.2 s
 
count = 1
 
====== b) BEEP Sequence - 5 beeps ======
<syntaxhighlight lang="json" line="1">
{
"id": 1779789836000,
"origin": "APP",
"task": {
    "action": "BEEP",
    "params": {
      "duration_s": 1,
      "count": 5,
      "gap_s": <GAP_BETWEEN_BEEPS>
  }
}
}
</syntaxhighlight>'''Buzzer State'''
[[File:5 beeps.svg|left|frameless|700x700px]]
 
 
 
 
 
duration_s = 1.0s
 
gap_s = 0.5s
 
count = 5
 
====== c) Infinite BEEP Sequence ======
 
This happens when: "count": 0<syntaxhighlight lang="json" line="1">
{
"id": 1779789836000,
"origin": "APP",
"task": {
    "action": "BEEP",
    "params": {
      "duration_s": 1,
      "count": 0,
      "gap_s": 0.5
  }
}
}
</syntaxhighlight>'''Buzzer State'''
[[File:Infinite_Beeps.svg|frameless|606x606px]]
duration_s = 1.0
gap_s = 0.5
 
count = 0
 
====== d) Continuous BEEP ======
In continuous mode, the buzzer remains ON until a STOP command is received.<syntaxhighlight lang="json" line="1">
{
"id": 1779789836000,
"origin": "APP",
"task": {
    "action": "BEEP",
    "params": {
      "mode": "continuous",
  }
}
}
</syntaxhighlight>'''Buzzer State'''
 
[[File:Continous beep.svg|frameless|600x600px]]
 
mode = continuous
 
====== e) STOP ======
The STOP command immediately forces the buzzer to OFF.
 
'''Buzzer State'''
 
[[File:Stop beep.svg|frameless|600x600px]]
 
After STOP, the buzzer is forced to OFF.
 
==== 24.12 INA232 actor ====
 
===== 24.12.1 Overview =====
The '''INA Actor''' is responsible for reading the ATLAS INA232 power monitor and publishing the measuredelectrical values through MQTT.
 
The actor publishes:
{| class="wikitable"
|'''Value'''
|'''Unit'''
|'''Description'''
|-
|voltage_v
|V
|Measured bus/input voltage
|-
|current_a
|A
|Measured current
|-
|power_w
|W
|Measured/calculated power
|}
The INA232 is a current, voltage, and power monitor with an I²C/SMBus interface. It reports current, busvoltage, and power values through internal registers. The calibration register must be configured to obtainvalid current and power results.
 
===== 24.12.2 Actor Behaviour =====
The INA Actor shall:
 
1. Start with a valid INA configuration.
 
2. Configure the INA232 device.
 
3. Read voltage, current and power once per second.
 
4. Publish the values to: '''ina/runtime/out'''
 
The actor does '''not''' need a request every second.
 
The publication is automatic and periodic.
 
===== 24.12.3 Required Configuration =====
The actor requires a small configuration to correctly read and convert the INA232 measurements.
{| class="wikitable"
|'''Field'''
|'''Type'''
|'''Required'''
|'''Description'''
|-
|enabled
|boolean
|Yes
|Enables or disables the INA actor
|-
|address
|string /integer
|Yes
|I²C address of the INA232 device
|-
|shunt_ohm
|number
|Yes
|Value of the shunt resistor in ohms
|-
|max_current_a
|number
|Yes
|Maximum expected current, used forcalibration
|-
|adcrange
|integer
|No
|INA232 shunt voltage range selection
|-
|publish_interval_ms
|integer
|Yes
|Runtime publish interval in milliseconds
|-
|rail_name
|string
|No
|Logical name of the monitored power rail
|}
 
* '''Default configuration'''
<syntaxhighlight lang="json" line="1">
{
  "enabled": true,
  "address": "0x40",
  "shunt_ohm": 0.020,
  "publish_interval_ms": 1000,
  "rail_name": "atlas_input_power"
}
</syntaxhighlight>
 
===== 24.12.4 Configuration domain =====
Configuration messages are sent to:
 
'''ina/config/in'''
 
Configuration replies are published on:
 
'''ina/config/out'''
 
'''- GET_CONFIG'''
 
Returns the current INA Actor configuration
 
'''Request'''<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_CONFIG"
  }
}
</syntaxhighlight>'''Response'''<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "INA",
  "task": {
    "action": "GET_CONFIG",
    "taskResult": {
      "success": true,
      "configured": true,
      "enabled": true,
      "address": "0x40",
      "shunt_ohm": 0.020,
      "publish_interval_ms": 1000
    }
  }
}
</syntaxhighlight>
 
===== 24.12.5 Runtime domain =====
Runtime messages are sent to:
 
'''ina/runtime/in'''
 
Runtime replies are published on:
 
'''ina/runtime/out'''
 
'''- Manual Runtime read'''
 
'''Request'''<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_POWER"
  }
}
</syntaxhighlight>'''Response'''<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "INA",
  "task": {
    "action": "GET_POWER",
    "taskResult": {
      "success": true,
      "voltage_v": 24.12,
      "current_a": 0.481,
      "power_w": 11.6
    }
  }
}
</syntaxhighlight>'''- Automatic Runtime Publication'''
 
Publish topic:
 
'''ina/runtime/out'''
 
Period: 1000 ms === 1s
 
'''Response payload'''<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "INA",
  "task": {
    "action": "PUBLISH_POWER",
    "taskResult": {
      "success": true,
      "voltage_v": 24.12,
      "current_a": 0.481,
      "power_w": 11.6
     }
   }
}
</syntaxhighlight>
{| class="wikitable"
|'''Field'''
|'''Type'''
|'''Required'''
|'''Description'''
|-
|success
|boolean
| -
|Indicates whether the read operation succeeded
|-
|voltage_v
|number
|V
|Measured bus/input voltage
|-
|current_a
|number
|A
|Measured current
|-
|power_w
|number
|W
|Measured power
|}
 
==== <big>24.13 Modem Actor</big> ====
 
===== 24.13.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtainmodem (LTE) data. Connecting to the broker for this area requires no credentials.
 
===== 24.13.2 Mobile (LTE Modem) =====
The Mobile actor manages the LTE modem using ModemManager ('''mmcli'''). It allows monitoring modem status, configuring connectivity (APN, operator,network mode), and performing diagnostics.
 
===== 24.13.3 Scan Operators =====
Scans available network operators (requires SIM and modem enabled).
 
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SCAN_OPERATORS"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "operators": [
        {
          "id": "26801",
          "name": "vodafone P",
          "status": "available"
        },
        {
          "id": "26806",
          "name": "MEO",
          "status": "available"
        }
      ]
    }
  }
}
</syntaxhighlight>
 
===== 24.13.4 Set Operator =====
The supported modes are:
 
* auto → modem selects de operator automatically ('''default''').
* manual→ user forces a specific operator using '''operator_id'''.
 
- Operators are identified using '''MCC + MNC codes''':
{| class="wikitable"
|'''Operator'''
|'''Code'''
|'''Country'''
|-
|Vodafone PT
|26801
|Portugal
|-
|MEO
|26806
|Portugal
|-
|NOS
|26803
|Portugal
|}
These values are obtained dynamically via SCAN_OPERATORS
 
* '''Recommendations:'''
 
Default should always be '''auto'''
 
Use '''manual''' only when:
 
- You need to force roaming behavior
 
- You want to lock to a specific network for stability/testing
 
====== '''Auto Selection''' ======
'''Req-Topic''': modem/config/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_OPERATOR",
    "taskParams": {
      "mode": "auto"
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true
    }
  }
}
</syntaxhighlight>
 
====== Manual Selection ======
'''Req-Topic''': modem/config/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_OPERATOR",
    "taskParams": {
      "mode": "manual",
      "operator_id": "26801"
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true
    }
  }
}
</syntaxhighlight>
 
===== 24.13.5 Set APN Configuration =====
Supports automatic (predefined APN) or custom configuration.
 
====== Actual Behavior ======
When '''SET_APN''' is executed, the system performs the following sequence:
 
# '''Disconnects the current data connection''' (if connected)
# Applies the new APN configuration
# Initiates a new connection using the provided APN
# Waits until the modem reaches '''connected state'''
 
This means a '''full reconnection is automatically performed'''.
 
No additional RESET or manual reconnection is required.
 
====== Impact & Considerations ======
 
* Active data connection is '''interrupted'''
* Ongoing communications (MQTT, HTTP, VPN, etc.) will be '''dropped'''
* IP address may change after reconnection
* Operation may take '''several seconds (typically 5–20s)'''
* If connection fails, the modem may remain '''disconnected'''
 
====== Known APNs ======
{| class="wikitable"
|'''Operator'''
|'''APN CONF'''
'''NAME'''
|'''APN'''
|'''PROXY'''
|'''PORT'''
|'''MCC'''
|'''MNC'''
|'''AUTH'''
'''TYPE'''
|'''APN'''
'''TYPE'''
|'''CARRIER'''
|'''OBS.'''
|-
|MEO, UZO
| --
|internet
| --
| --
| --
| --
| --
| --
| --
| --
|-
|1nce
| --
|iot.1nce.net
| --
| --
| --
| --
| --
| --
| --
| --
|-
|Vodafone
|Vodafone
Internet
|net2.vodafone.pt
|iproxy.vodafone.pt
|80
|268
|01
|PAP
|default
|unspecified
|[https://ajuda.vodafone.pt/manuais/vodafone/smart-4g/explorar/configure-o-telefone-para-internet Docs]
|}
 
====== Supported Modes ======
 
* auto
* custom
 
{| class="wikitable"
|'''Mode'''
|'''Description'''
|-
|auto
|Uses modem default / SIM-provided APN
|-
|custom
|Uses user-defined APN credentials
|}
'''- Auto APN (e.g. 1NCE)'''
 
Uses the default APN embedded in the modem or provided by the SIM.
 
'''Req-Topic''': modem/config/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_APN",
    "taskParams": {
      "mode": "auto"
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "apn": "internet",
      "success": true
    }
  }
}
</syntaxhighlight>'''- Custom APN'''
 
Allows full control over APN configuration.
 
'''Req-Topic''': modem/config/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_APN",
    "taskParams": {
      "mode": "custom",
      "apn": "internet",
      "user": "user",
      "password": "pass"
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "apn": "internet",
      "success": true
    }
  }
}
</syntaxhighlight>
 
===== 24.13.6 Get Modem Status =====
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_STATUS"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "modem": {
        "present": true,
        "enabled": true,
        "state": "registered",
        "signal": 34,
        "access_tech": "lte",
        "operator": "vodafone P",
        "sim": "ready"
      }
    }
  }
}
</syntaxhighlight>
 
===== 24.13.7 Enable / Disable Modem =====
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_MODEM_STATE",
    "taskParams": {
      "enabled": true
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "enabled": true,
      "success": true
    }
  }
}
</syntaxhighlight>
 
===== 24.13.8 Reset Modem =====
Performs a full modem reset and recovery sequence.
 
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "RESET"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true
    }
  }
}
</syntaxhighlight>
 
====== Actual Behavior ======
When RESET is executed, the system performs a '''complete modem restart flow''':
 
# Executes system-level reset: '''ltectl reset-modem'''
# The modem '''disappears from the system (USB re-enumeration)'''
# The system waits for the modem to '''reappear'''
# Re-discovers the modem path
# Waits until the modem becomes '''ready'''
# Waits until the modem is '''connected again'''
 
This is a '''full recovery sequence''', including automatic reconnection.
 
====== Impact on active connection ======
 
* Active data connection is '''immediately terminated'''
* All ongoing communications (MQTT, VPN, HTTP, etc.) will be '''interrupted'''
* Modem temporarily '''disappears from the system'''
* A new network registration is performed
* IP address will '''likely change'''
* Total recovery time may take '''10–120 seconds'''
 
====== When to use ======
Use '''RESET''' only when:
 
* Modem is stuck in '''searching''' or not registering
* Connected but no data traffic is possible
* APN/operator changes are not taking effect
* Modem becomes unresponsive or unstable
 
====== When NOT to Use ======
Avoid using RESET :
 
* During OTA updates or file uploads
* During critical real-time operations
* If a simple reconnect ( SET_MODEM_STATE ) is sufficient
 
====== Application Considerations ======
'''Before RESET'''
 
* Ensure no critical operations are ongoing
* Persist any unsent or buffered data
* Expect loss of connectivity
 
'''After RESET'''
 
* Wait for modem to fully recover (can take up to ~2 minutes)
* Re-check modem status using: '''GET_STATUS'''
* Re-establish application-level connections: '''MQTT'''; '''VPN''' an '''Cloud sessions'''
 
===== 24.13.9 Set Network Mode =====
Configures allowed radio technologies
 
Supported values:
 
* 2g
* 3g
* 4g
* auto
 
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_NETWORK_MODE",
    "taskParams": {
      "mode": "4g"
    }
  }
}</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "mode": "4g",
      "success": true
    }
  }
}
</syntaxhighlight>
 
===== 24.13.10 Get Signal Strength =====
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_SIGNAL"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "signal": 34,
      "unit": "%"
    }
  }
}
</syntaxhighlight>
 
===== 24.13.11 Get SIM card info =====
'''GET_SIM_INFO''' is a '''runtime action''' used to read SIM card information from the modem through ModemManager.
 
This action is '''read-only'''. It does not change the modem state, APN, operator, bearer, or NetworkManager configuration.
 
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_SIM_INFO"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "modem-actor",
  "task": {
    "taskResult": {
      "success": true,
      "sim": {
        "id": "0",
        "path": "/org/freedesktop/ModemManager1/SIM/0",
        "active": true,
        "iccid": "8935101234567890123",
        "imsi": "268060123456789",
        "operator_id": "26806",
        "operator_name": "MEO",
        "emergency_numbers": [
          "112"
        ],
        "preferred_networks": [
          "operator-code: 42507, access-technologies: gsm, umts, lte",
          "operator-code: 20810, access-technologies: gsm, umts, lte",
          "operator-code: 64710, access-technologies: gsm, umts, lte",
          "operator-code: 37001, access-technologies: gsm, umts, lte",
          "operator-code: 34002, access-technologies: gsm, umts, lte"
        ]
      }
    }
  }
}
</syntaxhighlight>
{| class="wikitable"
|'''Field'''
|'''Type'''
|'''Description'''
|-
|id
| number / string
|Same request ID received in the input payload.
|-
|origin
| string
|Actor name, usually '''modem-actor'''.
|-
|task.taskResult.success
|boolean
|Indicates if the SIM information was read successfully.
|-
|task.taskResult.sim.id
|string
|SIM object ID used by ModemManager. Usually 0.
|-
|task.taskResult.sim.path
|string
|ModemManager DBus path for the SIM object.
|-
|task.taskResult.sim.active
|boolean / null
|Indicates if the SIM is active, when available.
|-
|task.taskResult.sim.iccid
|string / null
|SIM ICCID / SIM identifier. This is the physical SIM card identifier.
|-
|task.taskResult.sim.imsi
|string / null
|IMSI associated with the SIM subscription.
|-
|task.taskResult.sim.operator_id
|string / null
|Mobile operator identifier from the SIM, when available.
|-
|task.taskResult.sim.operator_name
|string / null
|Operator name from the SIM, when available.
|-
|task.taskResult.sim.emergency_numbers
|array
|Emergency numbers reported by the SIM/modem.
|-
|task.taskResult.sim.preferred_networks
|array
|Preferred networks stored on the SIM, when available.
|}
 
===== 24.13.12 Test Modem =====
Performs a basic diagnostic test:
 
* Modem detection
* SIM presence
* Network registration
* Data connectivity
 
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
"id": "<TIMESTAMP>",
"origin": "APP",
"task": {
  "action": "TEST"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "hw": true,
      "sim": true,
      "network": true,
      "data": true
    }
  }
}
</syntaxhighlight>
 
===== 24.13.13 Speed Test =====
Performs a '''low-data network speed test''' over the modem interface.
 
This command does '''not''' run a full bandwidth benchmark.
 
Instead, it performs a '''short and capped download burst''' on interface '''wwan0''' , measures the number of received bytes during a fixed time window, and
 
returns an '''estimated download speed''' together with '''latency''' and a '''confidence level'''.
 
This approach is designed for IoT / field devices using '''capped cellular SIM cards''', where a classic speed test would consume too much data.
 
'''Req-Topic''': modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SPEED_TEST"
  }
}
</syntaxhighlight>'''Reply-Topic''': modem/runtime/out
 
'''Success reply''':<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "download_mbps": 12.4,
      "success": true
    }
  }
}
</syntaxhighlight>'''Error reply'''
 
Example when the modem is not connected:<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "download_mbps": 12.4,
      "success": true
    }
  }
}
</syntaxhighlight>Example when an unexpected internal error occurs:<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "modem-actor",
  "task": {
    "taskResult": {
      "success": false,
      "reason": "unexpected_exception"
    }
  }
}
</syntaxhighlight>
 
====== '''Reply parameters''' ======
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Description'''
|-
|success
| boolean
|Indicates whether the speed test completed successfully. true = test executed, false = failed (see reason ).
|-
|download_mbps
| number
|Estimated download speed in '''megabits per second (Mbps)'''. Calculated from the number of bytes received on interface
'''wwan0''' during the measurement window.
|-
|bytes_sampled
|number
|Total number of '''received bytes''' measured on the modem interface ( '''wwan0''' ) during the test window. Used as the raw input
for speed calculation.
|-
|duration_s
|number
|Measurement window duration in seconds. Current implementation uses '''5 seconds'''.
|-
|latency_ms
|number
|null
|-
|confidence
|string
|Qualitative indicator of measurement reliability based on sampled bytes:• '''low''' → < 50,000 bytes• '''medium''' → 50,000–
299,999 bytes• '''high''' → ≥ 300,000 bytes
|-
|reason
|string
|Present only when '''success=false''' . Provides failure reason (e.g., '''not_connected (<state>)''' , '''unexpected_exception''' ).
|}
 
====== Data consumption notice ======
This command performs a '''real network download''' and therefore consumes mobile data.
 
Although the test is designed to be '''low-data''', it still generates traffic:
 
* Typical consumption per test: '''~100 KB to ~500 KB'''
* Latency measurement adds a negligible amount (ICMP ping)
 
'''Estimated data usage'''
{| class="wikitable"
|'''Frequency'''
|'''Estimated consumption'''
|-
|1 test/day (~100 KB)
| ~3 MB/month
|-
|1 test/day (~250 KB)
| ~7.5 MB/month
|-
|1 test/day (~500 KB)
|~15 MB/month
|}
 
====== Recommendation ======
For devices using '''capped SIM cards''', it is recommended to:
 
* Avoid running this test at high frequency
* Use signal and modem status ( '''mmcli''' ) for regular monitoring
* Reserve speed tests for:
 
- commissioning
 
- troubleshooting
 
- periodic health checks
 
'''Running frequent or extended tests may significantly impact the data allowance.'''
 
===== 24.13.14 Get Raw Modem Info (Reserved) =====
'''Req-Topic''': reserved/modem/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "modem-actor",
  "task": {
    "taskResult": {
      "success": false,
      "reason": "not_connected (registered)"
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': reserved/modem/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "DEV",
  "task": {
    "taskResult": {
      "raw": "mmcli -m 0 output..."
    }
  }
}
</syntaxhighlight>
 
===== 24.13.15 Example: Raw Modem Output ( mmcli ) =====
Command:
 
mmcli -m 0 --output-json
 
Example output:<syntaxhighlight lang="json" line="1">
{
  "modem": {
    "3gpp": {
      "5gnr": {
        "registration-settings": {
          "drx-cycle": "--",
          "mico-mode": "--"
        }
      },
      "enabled-locks": [],
      "eps": {
        "initial-bearer": {
          "dbus-path": "--",
          "settings": {
            "apn": "--",
            "ip-type": "--",
            "password": "--",
            "user": "--"
          }
        },
        "ue-mode-operation": "--"
      },
      "imei": "862636056280785",
      "network-rejection-access-technology": "--",
      "network-rejection-error": "--",
      "network-rejection-operator-id": "--",
      "network-rejection-operator-name": "--",
      "operator-code": "--",
      "operator-name": "--",
      "packet-service-state": "--",
      "pco": "--",
      "registration-state": "--"
    },
    "cdma": {
      "activation-state": "--",
      "cdma1x-registration-state": "--",
      "esn": "--",
      "evdo-registration-state": "--",
      "meid": "--",
      "nid": "--",
      "sid": "--"
    },
    "dbus-path": "/org/freedesktop/ModemManager1/Modem/0",
    "generic": {
      "access-technologies": [],
      "bearers": [],
      "carrier-configuration": "ROW_Gen_VoLTE",
      "carrier-configuration-revision": "05010822",
      "current-bands": [
        "egsm",
        "dcs",
        "pcs",
        "g850",
        "utran-1",
        "utran-4",
        "utran-6",
        "utran-5",
        "utran-8",
        "utran-2",
        "eutran-1",
        "eutran-2",
        "eutran-3",
        "eutran-4",
        "eutran-5",
        "eutran-7",
        "eutran-8",
        "eutran-12",
        "eutran-13",
        "eutran-18",
        "eutran-19",
        "eutran-20",
        "eutran-25",
        "eutran-26",
        "eutran-28",
        "eutran-34",
        "eutran-38",
        "eutran-39",
        "eutran-40",
        "eutran-41",
        "eutran-66",
        "utran-19"
      ],
      "current-capabilities": [
        "gsm-umts, lte"
      ],
      "current-modes": "allowed: 4g; preferred: none",
      "device": "/sys/devices/platform/scb/fe9c0000.xhci/usb1/1-1/1-1.4",
      "device-identifier": "2c759b7021f62d2e26973150063ea040b3662a65",
      "drivers": [
        "option",
        "qmi_wwan"
      ],
      "equipment-identifier": "862636056280785",
      "hardware-revision": "10000",
      "manufacturer": "QUALCOMM INCORPORATED",
      "model": "SIMCOM_SIM7600G-H",
      "own-numbers": [],
      "physdev": "/sys/devices/platform/scb/fe9c0000.xhci/usb1/1-1/1-1.4",
      "plugin": "simtech",
      "ports": [
        "cdc-wdm0 (qmi)",
        "ttyUSB0 (ignored)",
        "ttyUSB1 (gps)",
        "ttyUSB2 (at)",
        "ttyUSB3 (at)",
        "ttyUSB4 (audio)",
        "wwan0 (net)"
      ],
      "power-state": "on",
      "primary-port": "cdc-wdm0",
      "primary-sim-slot": "1",
      "revision": "LE20B04SIM7600G22",
      "signal-quality": {
        "recent": "yes",
        "value": "0"
      },
      "sim": "/org/freedesktop/ModemManager1/SIM/0",
      "sim-slots": [
        "/org/freedesktop/ModemManager1/SIM/0",
        "/"
      ],
      "state": "failed",
      "state-failed-reason": "sim-missing",
      "supported-bands": [
        "egsm",
        "dcs",
        "pcs",
        "g850",
        "utran-1",
        "utran-4",
        "utran-6",
        "utran-5",
        "utran-8",
        "utran-2",
        "eutran-1",
        "eutran-2",
        "eutran-3",
        "eutran-4",
        "eutran-5",
        "eutran-7",
        "eutran-8",
        "eutran-12",
        "eutran-13",
        "eutran-18",
        "eutran-19",
        "eutran-20",
        "eutran-25",
        "eutran-26",
        "eutran-28",
        "eutran-34",
        "eutran-38",
        "eutran-39",
        "eutran-40",
        "eutran-41",
        "eutran-66",
        "utran-19"
      ],
      "supported-capabilities": [
        "gsm-umts, lte"
      ],
      "supported-ip-families": [
        "ipv4",
        "ipv6",
        "ipv4v6"
      ],
      "supported-modes": [
        "allowed: 2g; preferred: none",
        "allowed: 3g; preferred: none",
        "allowed: 4g; preferred: none",
        "allowed: 2g, 3g; preferred: 3g",
        "allowed: 2g, 3g; preferred: 2g",
        "allowed: 2g, 4g; preferred: 4g",
        "allowed: 2g, 4g; preferred: 2g",
        "allowed: 3g, 4g; preferred: 4g",
        "allowed: 3g, 4g; preferred: 3g",
        "allowed: 2g, 3g, 4g; preferred: 4g",
        "allowed: 2g, 3g, 4g; preferred: 3g",
        "allowed: 2g, 3g, 4g; preferred: 2g"
      ],
      "unlock-required": "--",
      "unlock-retries": []
    }
  }
}
</syntaxhighlight>
 
====== Field Reference - mmcli -m 0 --output-json ======
{| class="wikitable"
|'''JSON Path'''
|'''Meaning'''
|'''Example Value'''
|'''Notes / Interpretation'''
|-
|modem.dbus-path
| Internal modem path
|/org/.../Modem/0
|Used by mmcli ( -m 0 )
|-
|modem.generic.manufacturer
| Modem vendor
|QUALCOMM INCORPORATED
|Hardware info
|-
|modem.generic.model
|Modem model
|SIM7600G-H
|
|-
|modem.generic.revision
|Firmware version
|LE20B04SIM7600G22
|Useful for debugging
|-
|modem.generic.device
|Linux device path
|/sys/devices/...
|USB device
|-
|modem.generic.drivers
|Kernel drivers
|option, qmi_wwan
|Must be present
|-
|modem.generic.primary-port
|Control interface
|cdc-wdm0
|Critical (QMI control)
|-
|modem.generic.ports
|Available interfaces
|ttyUSB*, wwan0
|Data + AT + GPS
|-
|modem.generic.power-state
|Power status
|on
|
|-
|modem.generic.state
|Modem state
|failed
|Main status field
|-
|modem.generic.state-failed-reason
|Failure reason
|sim-missing
|Root cause of failure
|-
|modem.generic.signal-quality.value
|Signal strength (%)
|0
|0 = no signal
|-
|modem.generic.current-capabilities
|Active radio tech
|gsm-umts, lte
|
|-
|modem.generic.current-modes
|Active mode
|allowed: 4g
|Controlled via API
|-
|modem.generic.current-bands
|Active frequency bands
|[eutran-1, ...]
|Coverage related
|-
|modem.generic.supported-bands
|Supported bands
|[eutran-*, utran-*]
|Hardware capability
|-
|modem.generic.supported-ip-families
|IP support
|ipv4, ipv6, ipv4v6
|
|-
|modem.generic.sim
|SIM path
|/org/.../SIM/0
|
|-
|modem.generic.sim-slots
|SIM slots
|[slot1, slot2]
|Slot 2 empty here
|-
|modem.generic.primary-sim-slot
|Active SIM slot
|1
|
|-
|modem.generic.bearers
|Active data sessions
|[ ]
|Empty = no connection
|-
|modem.3gpp.imei
|Device IMEI
|862636056280785
|Unique identifier
|-
|modem.3gpp.operator-name
|Network name
| --
|Not available (no SIM)
|-
|modem.3gpp.operator-code
|MCC/MNC
| --
|Not available
|-
|modem.3gpp.registration-state
|Network state
| --
|Not registered
|-
|modem.3gpp.packet-service-state
|Data service state
| --
|No data session
|-
|modem.3gpp.eps.initial-bearer.settings.apn
|APN
| --
|Not set / no connection
|}
 
===== 24.13.16 Notes: =====
 
* If no modem is detected: '''Reply-Topic''': modem/runtime/out
<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "modem": {
        "present": false
      }
    }
  }
}
</syntaxhighlight>
 
* If SIM is locked or missing: '''Reply-Topic''': modem/runtime/out
<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "modem": {
        "sim": "locked"
      }
    }
  }
}
</syntaxhighlight>
 
* Operator scan may take several seconds and should be handled asynchronously.
* Some actions require:
 
- SIM card inserted
 
- Modem enabled
 
- '''cdc-wdm0''' interface available
 
* Signal strength is reported as percentage and may be cached by ModemActor.
 
==== <big>24.14 CANopen Actor</big> ====
 
===== 24.14.1 App Interfacing =====
User App interface and functionalities exposed to the open part of the MQTT broker.
 
The CANopen Actor provides a generic protocol interface to CANopen devices.
 
The actor does NOT interpret device-specific meaning (Object Dictionary semantics).
 
It only handles communication (HOW to talk).
 
===== 24.14.2 Configuration =====
 
====== '''Configure CANopen Nodes''' ======
'''Req-Topic''': canopenRM8007/config/in
 
Stores CANopen defaults and logical node configuration inside the actor.<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "CONFIG_CANOPEN",
    "taskParams": {
      "defaults": {
        "sdo_timeout": "<SDO_TIMEOUT>"
      },
      "nodes": {
        "<NODE_NAME>": {
          "node_id": "<NODE_ID>",
          "steps_per_rev": "<STEPS_PER_REV>"
        }
      }
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/config/out<syntaxhighlight lang="json">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "CONFIG_CANOPEN",
    "taskResult": {
      "defaults": {
        "success": true
      },
      "motor_1": {
        "success": true
      }
    }
  }
}
</syntaxhighlight>'''Request Parameters'''
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"1777041089180"
|Unique request identifier. The same value isreturned in the response, allowing the applicationto match requests and responses.
|-
|origin
| string
|No
|"APP"
|Identifies who sent the request. Common values canbe
'''APP''', '''NodeRED''', '''CLI''', or '''TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the CANopencommand alias and parameters.
|-
|task.alias
|string
|Yes
|"CONFIG_CANOPEN"
|Defines the command to execute. For this section,the alias must be
'''CONFIG_CANOPEN'''.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the configuration data to store inside theCANopen actor.
|-
|task.taskParams.defaults
|object
|No
|{ "sdo_timeout":2.0 }
|Defines default CANopen settings used by the actorwhen no command-specific value is provided.
|-
|task.taskParams.defaults.sdo_timeout
|number
|No
|2.0
|Default timeout, in seconds, used for SDOoperations. For example, '''2.0'''
means the actor waitsup to 2 seconds for an SDO response.
|-
|task.taskParams.nodes
|object
|Yes
|<nowiki>{ "motor_1": {...}}</nowiki>
|List of logical CANopen nodes known by the actor.Each key is a user-defined node name.
|-
|task.taskParams.nodes.<NODE_NAME>
|object
|Yes
|"motor_1"
|Logical name used to reference a node later withoutrepeatedly sending its
'''node_id'''.
|-
|task.taskParams.nodes.<NODE_NAME>.node_id
|integer
|Yes
|5
|CANopen node ID on the CAN bus. Valid CANopennode IDs are normally in the range
'''1..127'''.
|-
|task.taskParams.nodes.<NODE_NAME>.steps_per_rev
|integer
|Recommended
|4096
|Number of raw position counts corresponding toone full mechanical revolution, 360°. The actor usesthis later to convert raw position into revolutions and angle_deg.
|}
'''Response Parameters'''
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"1777041089180"
|Same request identifier received in the request. Used to correlate the
response with the original command.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response. For successful
handler replies, this is canopen-actor.
|-
|task
|object
|{...}
|Main response object containing the executed alias and the command
result.
|-
|task.alias
|string
|"CONFIG_CANOPEN"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object containing the configuration outcome.
|-
|task.taskResult.defaults.success
|boolean
|true
|Indicates that the '''defaults''' configuration was successfully stored. This
field is present only if '''defaults''' was included in the request.
|-
|task.taskResult.<NODE_NAME>.success
|boolean
|true
|Indicates that the logical node configuration was successfully stored.
Example: '''taskResult.motor_1.success = true'''.
|-
|task.taskResult.success
|boolean
|true
|Generic success field. This appears when no specific '''defaults''' or '''nodes'''
result is generated.
|-
|task.taskResult.error
|string
|"unknown alias
CONFIG_X"
|Error description. This field is present only when the command fails.
|}
'''CONFIG_CANOPEN''' does not communicate with the CANopen device directly. It stores logical node configuration inside the actor so that later runtime
 
commands can refer to nodes by name instead of always sending the numeric '''node_id'''.
 
====== Configure one CANopen Transmit PDO ======
Configures a TPDO to transmit position data.
 
The handler validates '''pdo_num''' as '''1..4''', defaults '''map_index''' to '''0x6004''', '''map_subindex''' to '''0x00''', '''map_bits''' to '''32''', '''transmission_type''' to '''255''' , '''event_timer_ms'''
 
to '''20''', and '''inhibit_time_100us''' to '''0'''.
 
'''Req-Topic''': canopenRM8007/config/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "CONFIG_POSITION_TPDO",
    "taskParams": {
      "node_id": 5,
      "pdo_num": 1,
      "map_index": "0x6004",
      "map_subindex": "0x00",
      "map_bits": 32,
      "transmission_type": 255,
      "event_timer_ms": 2,
      "inhibit_time_100us": 20,
      "offset": 0,
      "size": 4,
      "signed": false,
      "steps_per_rev": 4096,
      "timeout": 2.0
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/config/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "CONFIG_POSITION_TPDO",
    "taskResult": {
      "success": true,
      "node_id": 5,
      "pdo_num": 1,
      "comm_index": 6144,
      "map_index": 6656,
      "mapped_object": "0x6004:00/32",
      "transmission_type": 255,
      "event_timer_ms": 2,
      "inhibit_time_100us": 20,
      "cob_id": 389
    }
  }
}
</syntaxhighlight>
 
====== Parameter description ======
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Default'''
|'''Description'''
|-
|node_id
| int
|Yes*
|—
|CANopen node ID.
|-
|node
| string
|Yes*
|—
|Logical node name configured previously with '''CONFIG_CANOPEN'''.
|-
|pdo_num
|int
|No
|1
|TPDO number. Valid range: '''1..4'''.
|-
|map_index
|int/string
|No
|0x6004
|Object dictionary index to map. Hex strings such as "'''0x6004'''" are
supported.
|-
|map_subindex
|int/string
|No
|0x00
|Object dictionary subindex.
|-
|map_bits
|int
|No
|32
|Number of mapped bits.
|-
|transmission_type
|int
|No
|255
|CANopen TPDO transmission type.
|-
|event_timer_ms
|int
|No
|20
|TPDO event timer in milliseconds.
|-
|inhibit_time_100us
|int
|No
|0
|Inhibit time in 100 μs units.
|-
|offset
|int
|No
|0
|Byte offset used later when decoding PDO position.
|-
|size
|int
|No
|4
|Number of bytes used later when decoding PDO position.
|-
|signed
|bool
|No
|false
|Whether decoded raw position should be interpreted as signed.
|-
|steps_per_rev
|int
|Recommended
|'''4096''' if saved into node
 
config
|Encoder steps per revolution.
|-
|timeout
|float
|No
|actor default
|SDO/NMT operation timeout.
|}
 
===== 24.14.3 Runtime Operations =====
Supported runtime aliases include <small>'''READ, READ_CONTINUOUS, STOP_READ_CONTINUOUS, READ_PDO_CONTINUOUS, STOP_READ_PDO_CONTINUOUS, PING, NMT_COMMAND, SDO_READ, SDO_WRITE, READ_HEARTBEAT, RECV_PDO, RECV_EMCY'''</small>, and <small>'''QUERY_NODE_INFO'''</small><small>'''.'''</small>
 
====== NMT Control ======
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "CONFIG_CANOPEN",
    "taskParams": {
      "defaults": {
        "sdo_timeout": "<SDO_TIMEOUT>"
      },
      "nodes": {
        "<NODE_NAME>": {
          "node_id": "<NODE_ID>",
          "steps_per_rev": "<STEPS_PER_REV>"
        }
      }
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "NMT_COMMAND",
    "taskResult": {
      "success": true,
      "id": "nmt-start-node5",
      "node_id": 5,
      "command": "START",
      "confirmed": true,
      "state": null
    }
  }
}
</syntaxhighlight>
 
* '''Supported NMT Commands'''
 
{| class="wikitable"
|'''Command'''
|'''Meaning'''
|'''Notes'''
|-
|START
| Puts the node into Operational state.
|If '''wait''' = '''true''', the actor waits for heartbeat state '''OPERATIONAL'''.
|-
|STOP
| Puts the node into Stopped state.
|If '''wait''' = '''true''', the actor waits for heartbeat state '''STOPPED'''.
|-
|PRE_OP
|Puts the node into Pre-Operational state.
|Used before operations such as PDO remapping.
|-
|PRE-OP
|Same as '''PRE_OP'''.
|Alternative accepted spelling.
|-
|PREOP
|Same as '''PRE_OP'''.
|Alternative accepted spelling.
|-
|PRE_OPERATIONAL
|Same as '''PRE_OP'''.
|Alternative accepted spelling.
|-
|RESET_NODE
|Resets the CANopen node application.
|If '''wait''' = '''true''', the actor waits for boot-up heartbeat.
|-
|RESET
|Same as '''RESET_NODE'''.
|Alternative accepted spelling.
|-
|RESET_COMM
|Resets CANopen communication.
|Sends NMT reset communication command.
|}
 
* '''Request Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"<TIMESTAMP>"
|Unique request identifier. The same value is returned in the response.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request, for example '''APP''' , '''NodeRED''' , '''CLI''' , or
'''TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the command alias and parameters.
|-
|task.alias
|string
|Yes
|"NMT_COMMAND"
|Defines the command to execute. For this operation, it must be
'''NMT_COMMAND'''.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the NMT command parameters.
|-
|task.taskParams.node_id
|integer
|Yes
|5
|Numeric CANopen node ID that will receive the NMT command.
|-
|task.taskParams.nodeId
|integer
|Yes
|5
|Alternative spelling for '''node_id'''.
|-
|task.taskParams.node
|string
|Yes
|"motor_1"
|Logical node name previously configured with '''CONFIG_CANOPEN'''.
|-
|task.taskParams.command
|string
|No
|"START"
|NMT command to send. If omitted, the actor defaults to '''START'''.
|-
|task.taskParams.wait
|boolean
|No
|false
|If '''true''', the actor waits for heartbeat/state confirmation when supported. If
'''false''', the command is sent without waiting for confirmation.
|-
|task.taskParams.timeout
|number
|No
|5.0
|Timeout, in seconds, used when waiting for NMT confirmation.
Default is '''5.0'''.
|-
|task.taskParams.sdo_timeout
|number
|No
|2.0
|Internal timeout used when creating/updating the CANopen node wrapper.
Usually not required for basic NMT usage.
|}
 
* '''Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"<TIMESTAMP>"
|Same request identifier received in the request. Used to correlate request and
response.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"NMT_COMMAND"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object containing the NMT command result.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the actor successfully executed the NMT command.
|-
|task.taskResult.id
|string
|"nmt-start-node5"
|Internal/request ID returned by the CANopen RPC call. Usually matches the
original request '''id'''.
|-
|task.taskResult.node_id
|integer
|5
|CANopen node ID that received the NMT command.
|-
|task.taskResult.command
|string
|"START"
|NMT command that was executed. For aliases such as '''RESET''' , the response may
normalize the command to '''RESET_NODE'''.
|-
|task.taskResult.confirmed
|boolean
|true
|Indicates whether the command was considered successful. If '''wait''' = '''false''' , this
usually means the command was sent successfully. If '''wait''' = '''true''' , this means
 
the expected heartbeat/state confirmation was received.
|-
|task.taskResult.state
|string/null
|null
|Confirmed NMT state when '''wait''' = '''true''' and state confirmation is available.
Otherwise it is '''null''' . Possible values include '''OPERATIONAL''' , '''STOPPED''' , and '''PRE_OP'''.
|-
|task.taskResult.error
|string
|"unsupported NMT
command X"
|Error description. Present only when the command fails.
|}
 
====== SDO Read ======
Reads an object dictionary value using SDO upload.
 
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "SDO_READ",
    "taskParams": {
      "node_id": 5,
      "index": "0x6004",
      "subindex": "0x00",
      "timeout": 2.0
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "SDO_READ",
    "taskResult": {
      "success": true,
      "id": "sdo-read-position-node5",
      "node_id": 5,
      "index": 24580,
      "subindex": 0,
      "value": 123456
    }
  }
}
</syntaxhighlight>
 
* '''Request Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"<TIMESTAMP>"
|Unique request identifier. The same value is returned in the response.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request, for example '''APP''' , '''NodeRED''' , '''CLI''' , or
'''TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the command alias and parameters.
|-
|task.alias
|string
|Yes
|"SDO_READ"
|Defines the command to execute. For this operation, it must be '''SDO_READ'''.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the SDO read parameters.
|-
|task.taskParams.node_id
|integer
|Yes
|5
|Numeric CANopen node ID to read from.
|-
|task.taskParams.nodeId
|integer
|Yes
|5
|Alternative spelling for '''node_id'''.
|-
|task.taskParams.node
|string
|Yes
|"motor_1"
|Logical node name previously configured with '''CONFIG_CANOPEN'''.
|-
|task.taskParams.index
|integer/string
|Yes
|"0x6004"
|CANopen object dictionary index to read. Hex strings such as "'''0x6004'''"
are supported.
|-
|task.taskParams.subindex
|integer/string
|No
|"0x00"
|CANopen object dictionary subindex to read. If omitted, defaults to '''0'''.
|-
|task.taskParams.timeout
|number
|No
|2.0
|Timeout, in seconds, used for the SDO read operation. If omitted, the
actor default SDO timeout is used.
|}
 
* '''Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"<TIMESTAMP>"
|Same request identifier received in the request. Used to correlate request and
response.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"SDO_READ"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object containing the SDO read result.
task
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the SDO read was successful.
|-
|task.taskResult.id
|string
|"sdo-read-positionnode5"
|Internal/request ID returned by the CANopen RPC call. Usually matches the
original request '''id'''.
|-
|task.taskResult.node_id
|integer
|5
|CANopen node ID that was read.
|-
|task.taskResult.index
|integer
|24580
|Object dictionary index that was read, returned as decimal. Example: '''24580''' =
'''0x6004'''.
|-
|task.taskResult.subindex
|integer
|0
|Object dictionary subindex that was read.
|-
|task.taskResult.value
|integer
|123456
|Raw value returned by the SDO read operation.
task.
|-
|task.taskResult.error
|string
|"SDO timeout
0x6004:00"
|Error description. Present only when the command fails.
SDO
|}
 
* SDO Write
 
Writes an object dictionary value using SDO download.
 
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "SDO_WRITE",
    "taskParams": {
      "node_id": 5,
      "index": "0x6003",
      "subindex": "0x00",
      "value": 0,
      "size": 4,
      "timeout": 2.0
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "SDO_WRITE",
    "taskResult": {
      "success": true,
      "id": "sdo-write-node5",
      "node_id": 5,
      "index": 24579,
      "subindex": 0,
      "value": 0,
      "size": 4
    }
  }
}
</syntaxhighlight>
 
* '''Parameter descirption'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Default'''
|'''Description'''
|-
|node_id / nodeId / node
| int/string
|Yes
|—
|CANopen node reference.
|-
|index
| int/string
|Yes
|—
|Object dictionary index.
|-
|subindex
|int/string
|No
|0
|Object dictionary subindex.
|-
|value
|int/string
|Yes
|—
|Value to write.
|-
|size
|int
|No
|4
|Number of bytes: usually '''1''' , '''2''' , or '''4.'''
|-
|timeout
|float
|No
|actor default
|SDO timeout in seconds.
|}
 
* '''Request Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"<TIMESTAMP>"
|Unique request identifier. The same value is returned in the response.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request, for example '''APP''' , '''NodeRED''' , '''CLI''' , or
 
'''TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the command alias and parameters.
|-
|task.alias
|string
|Yes
|"SDO_WRITE"
|Defines the command to execute. For this operation, it must be
 
'''SDO_WRITE'''.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the SDO write parameters.
|-
|task.taskParams.node_id
|integer
|Yes*
|5
|Numeric CANopen node ID to write to.
|-
|task.taskParams.nodeId
|integer
|Yes*
|5
|Alternative spelling for '''node_id'''.
|-
|task.taskParams.node
|string
|Yes*
|"motor_1"
|Logical node name previously configured with '''CONFIG_CANOPEN.'''
|-
|task.taskParams.index
|integer/string
|Yes
|"0x6003"
|CANopen object dictionary index to write. Hex strings such as "'''0x6003'''"
 
are supported.
|-
|task.taskParams.subindex
|integer/string
|No
|"0x00"
|CANopen object dictionary subindex to write. If omitted, defaults to '''0'''.
|-
|task.taskParams.value
|integer/string
|Yes
|0
|Value to write into the selected object dictionary entry. Hex strings are
 
also supported.
|-
|task.taskParams.size
|integer
|No
|4
|Number of bytes to write. Valid values are normally '''1''' , '''2''' , '''3''' , or '''4''' . If
 
omitted, defaults to '''4'''.
|-
|task.taskParams.timeout
|number
|No
|2.0
|Timeout, in seconds, used for the SDO write operation. If omitted, the
 
actor default SDO timeout is used.
|}
 
* '''Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"<TIMESTAMP>"
|Same request identifier received in the request. Used to correlate request andresponse.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"SDO_WRITE"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object containing the SDO write result.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the SDO write was successful.
|-
|task.taskResult.id
|string
|"sdo-write-node5"
|Internal/request ID returned by the CANopen RPC call.
 
Usually matches theoriginal request '''id'''.
|-
|task.taskResult.node_id
|integer
|5
|CANopen node ID that was written to.
|-
|task.taskResult.index
|integer
|24579
|Object dictionary index that was written, returned as decimal.
 
Example: '''24579 =0x6003'''.
|-
|task.taskResult.subindex
|integer
|0
|Object dictionary subindex that was written.
|-
|task.taskResult.value
|integer
|0
|Value that was written.
|-
|task.taskResult.size
|integer
|4
|Number of bytes written.
|-
|task.taskResult.error
|string
|"SDO abort 0x6003:00 ->..."
|Error description. Present only when the command fails.
|}
 
====== Read Node State ======
Reads position and returns raw value, revolutions, and angle. Internally, this reads the configured position object, defaulting to
 
'''0x6004:00'''. '''If''' '''steps_per_rev''' is not provided, the owner reads '''0x6501:00''' to obtain it.
 
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "READ",
    "taskParams": {
      "node_id": 5,
      "index": "0x6004",
      "subindex": "0x00",
      "steps_per_rev": 4096,
      "timeout": 2.0
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ",
    "taskResult": {
      "success": true,
      "id": "read-node5",
      "node_id": 5,
      "raw": 1024,
      "steps_per_rev": 4096,
      "revolutions": 0.25,
      "angle_deg": 90.0,
      "index": 24580,
      "subindex": 0
    }
  }
}
</syntaxhighlight>
 
* '''Request Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"<TIMESTAMP>"
|Unique request identifier. The same value is returned in theresponse.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request, for example '''APP, NodeRED, CLI''', or '''TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the command alias andparameters.
|-
|task.alias
|string
|Yes
|"READ"
|Defines the command to execute. For this operation, it must be '''READ'''.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the position read parameters.
|-
|task.taskParams.node_id
|integer
|Yes*
|5
|Numeric CANopen node ID to read from.
|-
|task.taskParams.nodeId
|integer
|Yes*
|5
|Alternative spelling for '''node_id'''.
|-
|task.taskParams.node
|string
|Yes*
|"motor_1"
|Logical node name previously configured with '''CONFIG_CANOPEN'''.
|-
|task.taskParams.index
|integer/string
|No
|"0x6004"
|CANopen object dictionary index used as the raw positionsource. If omitted, defaults to '''0x6004'''.
|-
|task.taskParams.subindex
|integer/string
|No
|"0x00"
|CANopen object dictionary subindex used as the raw positionsource. If omitted, defaults to '''0x00'''.
|-
|task.taskParams.steps_per_rev
|integer
|Recommended
|4096
|Number of raw counts per mechanical revolution. Used tocalculate
 
'''revolutions''' and '''angle_deg'''. If omitted, the ownerattempts to read '''0x6501:00'''.
|-
|task.taskParams.timeout
|number
|No
|2.0
|Timeout, in seconds, used for the internal SDO reads. Ifomitted, the actor default SDO timeout is used.
|-
|task.taskParams.sdo_timeout
|number
|No
|2.0
|Internal SDO timeout used when creating/updating the nodewrapper. Usually not required.
|}
 
* '''Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"<TIMESTAMP>"
|Same request identifier received in the request. Used to correlate request andresponse.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"READ"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object containing the position read result.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the position read was successful.
|-
|task.taskResult.id
|string
|"read-node5"
|Internal/request ID returned by the CANopen RPC call. Usually matches theoriginal request '''id'''.
|-
|task.taskResult.node_id
|integer
|5
|CANopen node ID that was read.
|-
|task.taskResult.raw
|integer
|1024
|Raw position value read from the selected object dictionary entry.
|-
|task.taskResult.steps_per_rev
|integer
|4096
|Number of raw counts per revolution used for the conversion.
|-
|task.taskResult.revolutions
|number
|0.25
|Raw position converted into revolutions. Example: '''1024 / 4096 = 0.25'''.
|-
|task.taskResult.angle_deg
|number
|90.0
|Position inside one revolution, in degrees. Example: '''0.25 × 360 = 90°'''.
|-
|task.taskResult.index
|integer
|24580
|Object dictionary index read as the raw position source. Example: '''24580 =0x6004'''.
|-
|task.taskResult.subindex
|integer
|0
|Object dictionary subindex read as the raw position source.
|-
|task.taskResult.error
|string
|"SDO timeout0x6004:00"
|Error description. Present only when the command fails.
|}
 
====== READ SDO Continuous ======
Starts continuous SDO-based position reading.
 
The initial command returns an acknowledgement. After that, continuous samples are published repeatedly to '''canopen/runtime/out'''
 
The continuous loop requires a single node reference and requires '''steps_per_rev'''.
 
* '''Start request'''
 
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskParams": {
      "node_id": 5,
      "steps_per_rev": 4096,
      "index": "0x6004",
      "subindex": "0x00",
      "timeout": 0.2,
      "interval_ms": 20
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
// Start acknowledgement
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": true,
      "mode": "single",
      "interval_ms": 20
    }
  }
}
</syntaxhighlight><syntaxhighlight lang="json" line="1">
// Continuous sample response
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskResult": {
      "success": true,
      "node_id": 5,
      "angle_deg": 90.0,
      "steps_per_rev": 4096,
      "revolutions": 0.25,
      "raw": 1024,
      "index": 24580,
      "subindex": 0,
      "continuous": true,
      "request_id": "read-cont-node5"
    }
  }
}
</syntaxhighlight>
 
* '''Start Request Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"<TIMESTAMP>"
|Unique request identifier. Continuous sample responses include
 
this value as '''request_id'''.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request, for example '''APP''', '''NodeRED''',
 
'''CLI''', or '''TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the command alias and
 
parameters.
|-
|task.alias
|string
|Yes
|"READ_CONTINUOUS"
|Defines the command to execute. For this operation, it must be
 
'''READ_CONTINUOUS'''.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the continuous read parameters.
|-
|task.taskParams.node_id
|integer
|Yes*
|5
|Numeric CANopen node ID to read continuously.
|-
|task.taskParams.nodeId
|integer
|Yes*
|5
|Alternative spelling for '''node_id'''.
|-
|task.taskParams.node
|string
|Yes*
|"motor_1"
|Logical node name previously configured with '''CONFIG_CANOPEN'''.
|-
|task.taskParams.steps_per_rev
|integer
|Yes**
|4096
|Number of raw counts per mechanical revolution. Required by
 
the fast continuous read loop to calculate '''revolutions''' and
 
'''angle_deg'''.
|-
|task.taskParams.index
|integer/string
|No
|"0x6004"
|CANopen object dictionary index used as the raw position
 
source. If omitted, defaults to '''0x6004'''.
|-
|task.taskParams.subindex
|integer/string
|No
|"0x00"
|CANopen object dictionary subindex used as the raw position
 
source. If omitted, defaults to '''0x00'''.
|-
|task.taskParams.timeout
|number
|No
|0.2
|Timeout, in seconds, used for each fast SDO read cycle. If
 
omitted, defaults to '''0.2'''.
|-
|task.taskParams.interval_ms
|integer
|No
|20
|Delay between continuous read cycles, in milliseconds. If '''0''' , the
 
loop runs again immediately after each cycle yields control.
|-
|task.taskParams.action
|string
|No
|"START"
|Optional action. If set to '''STOP''' , '''OFF''' , '''CANCEL''' , or '''DISABLE''' , the
 
actor stops the continuous read loop instead of starting it.
|}
 
* '''Start Acknowledgement Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"<TIMESTAMP>"
|Same request identifier received in the start request.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"READ_CONTINUOUS"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object confirming that continuous reading was started.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the start command was accepted.
|-
|task.taskResult.running
|boolean
|true
|Indicates that the continuous read loop is running.
|-
|task.taskResult.mode
|string
|"single"
|Read mode. In this fast continuous path, a single node is used when '''node_id''' ,
 
'''nodeId''' , or '''node''' is provided.
|-
|task.taskResult.interval_ms
|integer
|20
|Configured delay between continuous read cycles, in milliseconds.
|-
|task.taskResult.error
|string
|"no configured nodes"
|Error description. Present only when the start command fails.
|}
 
* '''Continuous Sample Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| integer/string
|1777041089180
|Sample response ID generated by the actor for each read cycle.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the sample response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"READ_CONTINUOUS"
|Alias of the running continuous command.
|-
|task.taskResult
|object
|{...}
|Result object containing one continuous position sample.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether this specific read cycle was successful.
|-
|task.taskResult.node_id
|integer
|5
|CANopen node ID that was read.
|-
|task.taskResult.angle_deg
|number
|90.0
|Position inside one revolution, in degrees.
|-
|task.taskResult.steps_per_rev
|integer
|4096
|Number of raw counts per revolution used for conversion.
|-
|task.taskResult.revolutions
|number
|0.25
|Raw position converted into revolutions.
|-
|task.taskResult.raw
|integer
|1024
|Raw position value read from the node.
|-
|task.taskResult.index
|integer
|24580
|Object dictionary index read as the raw position source. Example: '''24580 ='''
 
'''0x6004'''.
|-
|task.taskResult.subindex
|integer
|0
|Object dictionary subindex read as the raw position source.
|-
|task.taskResult.continuous
|boolean
|true
|Marks this response as a continuous sample, not just the initial
 
acknowledgement.
|-
|task.taskResult.request_id
|string
|"read-cont-node5"
|Original request '''id''' that started the continuous loop. Useful to correlate
 
samples with the start command.
|-
|task.taskResult.error
|string
|"operation failed"
|Error description for a failed sample. Present only when a read cycle fails.
|}
 
====== Stop request ======
You can stop using either '''STOP_READ_CONTINUOUS''' :
 
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "STOP_READ_CONTINUOUS",
    "taskParams": {}
  }
}
</syntaxhighlight>Or by sending '''READ_CONTINUOUS''' with '''action: "STOP"''' :<syntaxhighlight lang="json" line="1">
{
  "id": "stop-read-cont",
  "origin": "APP",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskParams": {
      "action": "STOP"
    }
  }
}
</syntaxhighlight>'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "stop-read-cont",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": false,
      "stopped": true
    }
  }
}
</syntaxhighlight>
 
* '''Stop Request Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"stop-read-cont"
|Unique request identifier.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request.
|-
|task.alias
|string
|Yes
|"READ_CONTINUOUS" or
 
"STOP_READ_CONTINUOUS"
|Command used to stop the continuous read loop.
|-
|task.taskParams.action
|string
|No
|"STOP"
|When using '''READ_CONTINUOUS''' , set '''action''' to '''STOP''' , '''OFF''' , '''CANCEL''' ,
 
or '''DISABLE''' to stop the loop. Not required when using
 
'''STOP_READ_CONTINUOUS'''.
|}
 
* '''Stop Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"stop-read-cont"
|Same request identifier received in the stop request.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task.alias
|string
|"READ_CONTINUOUS"
|Alias returned by the stop handler.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the stop request was processed successfully.
|-
|task.taskResult.running
|boolean
|false
|Indicates that the continuous read loop is no longer running.
|-
|task.taskResult.stopped
|boolean
|true
|Indicates whether there was an active task that was actually stopped. If no continuous
 
task was running, this may be '''false'''.
|}
 
====== Continuous PDO Reading ======
Starts continuous PDO-based position reading.
 
This command does not perform repeated SDO reads. Instead, it waits for TPDO frames already being transmitted by the CANopen node.
 
Normally, the TPDO should be configured first using '''CONFIG_POSITION_TPDO'''.
 
The initial command returns an acknowledgement. After that, continuous sample responses are published repeatedly to: '''canopenRM8007/runtime/out'''
 
* '''Start Request'''
 
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskParams": {
      "node_id": 5,
      "pdo_num": 1,
      "steps_per_rev": 4096,
      "offset": 0,
      "size": 4,
      "signed": false,
      "timeout": 1.0,
      "interval_ms": 20
    }
  }
}
</syntaxhighlight>
 
* '''Start Acknowledgement'''
 
'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": true,
      "mode": "pdo",
      "pdo_num": 1,
      "interval_ms": 20
    }
  }
}
</syntaxhighlight>
 
* '''Continuous Sample Response'''
 
'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskResult": {
      "success": true,
      "node_id": 5,
      "pdo_num": 1,
      "angle_deg": 90.0,
      "steps_per_rev": 4096,
      "revolutions": 0.25,
      "raw": 1024,
      "data": [0, 4, 0, 0],
      "offset": 0,
      "size": 4,
      "signed": false,
      "continuous": true,
      "request_id": "read-pdo-cont-node5"
    }
  }
}
</syntaxhighlight>'''Start Request Parameters'''
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Required'''
|'''Example'''
|'''Description'''
|-
|id
| string
|Yes
|"<TIMESTAMP>"
|Unique request identifier. Continuous sample responses include
 
this value as '''request_id'''.
|-
|origin
| string
|No
|"APP"
|Identifies the sender of the request, for example '''APP , NodeRED ,'''
 
'''CLI , or TestClient'''.
|-
|task
|object
|Yes
|{...}
|Main command object containing the command alias and
 
parameters.
|-
|task.alias
|string
|Yes
|"READ_PDO_CONTINUOUS"
|Defines the command to execute.
|-
|task.taskParams
|object
|Yes
|{...}
|Contains the PDO continuous read parameters.
|-
|task.taskParams.node_id
|integer
|Yes*
|5
|Numeric CANopen node ID to read from.
|-
|task.taskParams.nodeId
|integer
|Yes*
|5
|Alternative spelling for '''node_id'''.
|-
|task.taskParams.node
|string
|Yes*
|"motor_1"
|Logical node name previously configured with '''CONFIG_CANOPEN'''. If
 
used, the actor can reuse saved '''steps_per_rev , pdo_num ,'''
 
'''offset , size''' , and '''signed''' values from the node configuration.
|-
|task.taskParams.pdo_num
|integer
|No
|1
|TPDO number to listen to. If omitted, defaults to '''1'''.
|-
|task.taskParams.steps_per_rev
|integer
|Yes**
|4096
|Number of raw position counts per mechanical revolution. Used
 
to convert '''raw''' into '''revolutions''' and '''angle_deg'''.
|-
|task.taskParams.offset
|integer
|No
|0
|Byte offset inside the PDO payload where the position value
 
starts.
|-
|task.taskParams.size
|integer
|No
|4
|Number of bytes to decode from the PDO payload. For a 32-bit
 
position value, use '''4'''.
|-
|task.taskParams.signed
|boolean
|No
|false
|Defines whether the raw value should be decoded as signed or
 
unsigned.
|-
|task.taskParams.timeout
|number
|No
|1.0
|Timeout, in seconds, while waiting for each TPDO frame. If no
 
TPDO is received within this time, the cycle fails.
|-
|task.taskParams.interval_ms
|integer
|No
|20
|Delay between read cycles, in milliseconds. If '''0''' , the loop
 
immediately starts the next cycle after yielding control.
|-
|task.taskParams.action
|string
|No
|"START"
|Optional action. If set to '''STOP , OFF , CANCEL , or DISABLE''' , the
 
actor stops the continuous loop instead of starting it.
|}
 
* '''Start Acknowledgement Response Parameters'''
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"<TIMESTAMP>"
|Same request identifier received in the start request.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"READ_PDO_CONTINUOUS"
|Alias of the command that was executed.
|-
|task.taskResult
|object
|{...}
|Result object confirming whether the continuous PDO read
 
was started.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the start command was accepted.
|-
|task.taskResult.running
|boolean
|true
|Indicates that the continuous PDO read loop is running.
|-
|task.taskResult.mode
|string
|"pdo"
|Indicates that the loop is using PDO reception mode.
|-
|task.taskResult.pdo_num
|integer
|1
|TPDO number being listened to.
|-
|task.taskResult.interval_ms
|integer
|20
|Configured delay between read cycles, in milliseconds.
|-
|task.taskResult.error
|string
|"'''READ_PDO_CONTINUOUS''' requires a single
 
node"
|Error description. Present only when the start command
 
fails.
|}
 
* '''Continuous Sample Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| integer/string
|1777041089180
|Sample response ID generated by the actor for each PDO read cycle.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the sample.
|-
|task
|object
|{...}
|Main response object.
|-
|task.alias
|string
|"READ_PDO_CONTINUOUS"
|Alias of the running continuous command.
 
task.
|-
|task.taskResult
|object
|{...}
|Result object containing one decoded PDO position sample.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether this specific PDO read cycle was successful.
|-
|task.taskResult.node_id
|integer
|5
|CANopen node ID that produced the TPDO.
|-
|task.taskResult.pdo_num
|integer
|1
|TPDO number received and decoded.
|-
|task.taskResult.angle_deg
|number
|90.0
|Position inside one revolution, in degrees.
|-
|task.taskResult.steps_per_rev
|integer
|4096
|Number of raw counts per revolution used for conversion.
|-
|task.taskResult.revolutions
|number
|0.25
|Raw position converted into revolutions. Example: '''1024 / 4096 = 0.25''' .
|-
|task.taskResult.raw
|integer
|1024
|Decoded raw position value from the PDO payload.
|-
|task.taskResult.data
|array
|[0, 4, 0, 0]
|Raw PDO payload bytes received from the CANopen node.
|-
|task.taskResult.offset
|integer
|0
|Byte offset used to extract the raw position value from '''data.'''
|-
|task.taskResult.size
|integer
|4
|Number of bytes decoded from '''data'''.
|-
|task.taskResult.signed
|boolean
|false
|Indicates whether the raw value was decoded as signed or unsigned.
|-
|task.taskResult.continuous
|boolean
|true
|Marks this response as a continuous sample.
|-
|task.taskResult.request_id
|string
|"read-pdo-cont-node5"
|Original request '''id''' that started the continuous loop. Useful to
 
correlate samples with the start command.
|-
|task.taskResult.error
|string
|"pdo operation failed"
|Error description. Present only when a sample fails.
|}
 
====== Stop Request ======
'''Req-Topic''': canopenRM8007/runtime/in<syntaxhighlight lang="json" line="1">
{
  "id": "stop-pdo-cont",
  "origin": "APP",
  "task": {
    "alias": "STOP_READ_PDO_CONTINUOUS",
    "taskParams": {}
  }
}
</syntaxhighlight>Alternative stop request using '''READ_PDO_CONTINUOUS''':<syntaxhighlight lang="json" line="1">
{
  "id": "stop-pdo-cont",
  "origin": "APP",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskParams": {
      "action": "STOP"
    }
  }
}
</syntaxhighlight>
 
====== '''Stop Response''' ======
'''Reply-Topic''': canopenRM8007/runtime/out<syntaxhighlight lang="json" line="1">
{
  "id": "stop-pdo-cont",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": false,
      "stopped": true
    }
  }
}
</syntaxhighlight>
 
* '''Stop Response Parameters'''
 
{| class="wikitable"
|'''Parameter'''
|'''Type'''
|'''Example'''
|'''Description'''
|-
|id
| string
|"stop-pdo-cont"
|Same request identifier received in the stop request.
|-
|origin
| string
|"canopen-actor"
|Identifies the component that generated the response.
|-
|task.alias
|string
|"READ_PDO_CONTINUOUS"
|Alias returned by the stop handler.
|-
|task.taskResult.success
|boolean
|true
|Indicates whether the stop request was processed successfully.
|-
|task.taskResult.running
|boolean
|false
|Indicates that the continuous PDO loop is no longer running.
|-
|task.taskResult.stopped
|boolean
|true
|Indicates whether there was an active continuous task that was actually stopped. If
 
no task was running, this may be '''false'''.
|}
 
====== Decode Logic ======
The received PDO payload is decoded using:
 
* '''offset''': first byte to read from the PDO payload;
* '''size''': number of bytes to read;
* '''signed''': whether the value is signed or unsigned;
* '''steps_per_rev''': scaling factor used to calculate revolutions and angle.
 
The raw value is decoded as little-endian:
 
'''raw = int.from_bytes(data[offset : offset + size], byteorder="little", signed=signed)'''
 
Then:
 
'''revolutions = raw / steps_per_rev'''
 
'''angle_deg = ((raw % steps_per_rev) / steps_per_rev) * 360.0'''
 
===== 24.14.4 Design Principles =====
 
* '''Protocol-Only Actor'''
 
The CANopen Actor is responsible for:
 
- CAN frame encoding/decoding;
 
- SDO communication;
 
- PDO reception (raw);
 
- NMT control;
 
- Heartbeat monitoring.
 
* '''No Device Semantics'''
 
The actor:
 
'''Does NOT know''':
 
- What 0x6004 represents;
 
- Units (RPM, mm, °C, etc.);
 
- Device-specific logic.
 
'''Only returns''':
 
- Raw values;
 
- Protocol-level responses.
 
* '''Node Management'''
 
- Nodes must be defined via configuration;


</syntaxhighlight>
- Actor maintains node state internally;


=== 34. Joystick Actor ===
- Supports multiple nodes simultaneously.


==== 34.1 App Interfacing ====
===== Summary =====
User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.
The CANopen Actor:


===== 34.1.1 Get all joystick pins state =====
- Implements '''CANopen protocol communication;'''


Req-Topic: joystick/runtime/in<syntaxhighlight lang="json">
- Provides '''generic MQTT interface;'''
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }


</syntaxhighlight>Reply-Topic: joystick//runtime/out
- Supports '''multi-node networks;'''


state: pressed/released<syntaxhighlight lang="json">
- Keeps '''strict separation between transport and semantics.'''
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "JLEFT": {
        "success": true,
        "state": "pressed"
      },
      "JRIGHT": {
        "success": true,
        "state": "released"
      },
      "JUP": {
        "success": true,
        "state": "released"
      },
      "JDOWN": {
        "success": true,
        "state": "released"
      },
      "JCENTER": {
        "success": true,
        "state": "released"
      }
    }
  }
}


</syntaxhighlight>


=== 35. Included Software Stack ===
=== 25. Included Software Stack ===




[[File:AtlasCode.svg|center|frameless|583x583px]]
[[File:AtlasCode.svg|center|frameless|583x583px]]


=== 36. Hardware Libraries ===
=== 26. Hardware Libraries ===
[IMAGE PLACEHOLDER]
[IMAGE PLACEHOLDER]


=== 37. Related Products ===
=== 27. Related Products ===
{| class="wikitable"
{| class="wikitable"
|'''PA'''
|'''PA'''
Line 2,069: Line 7,856:
|'''Requirements'''
|'''Requirements'''
|-
|-
|
|PA000000074
|
|[[SENSBLUE MONARCH|SENSBLUE MONARCH Gateway]]
|
|-
|
|
|
|-
|
|
|
|-
|
|
|
|-
|
|
|
|
|-
|-
|
|
|
|}
|}
{{SimilarProductsTable}}


=== 38. Accessories ===
=== 28. Accessories ===
{| class="wikitable"
{| class="wikitable"
|'''PA'''
|'''PA'''
Line 2,121: Line 7,890:
|}
|}


=== 39. Document History ===
=== 29. Document History ===
{| class="wikitable"
{| class="wikitable"
|'''Version'''
|'''Version'''
Line 2,140: Line 7,909:
|}
|}


=== 40. SENSBLUE ATLAS in-the-field ===
=== 30. SENSBLUE ATLAS in-the-field ===
[IMAGE PLACEHOLDER]
[IMAGE PLACEHOLDER]

Latest revision as of 15:21, 12 June 2026

Datasheet

1. Table of SENSBLUE ATLAS Reference ID Model Number

Paxxxxxxxx
PAxxxxxxxx

2. General Description

SENSBLUE ATLAS is a single board computer that connects sensors and assets, runs control logic and ships to production without platform changes.

Designed for industrial teams who need one dependable path from experiments to operations.

2.1 Key Features

Processor:

  • Raspberry Pi CM4 (quad-core Cortex-A72)

I/O:

  • 12 DIO (8 Digital Outputs and 4 Digital Input)
  • 6 AIO (4 Analog Inputs and 2 Analog Outputs)
  • 2 relays

Industrial Bus:

  • RS-485
  • CAN
  • 2× Ethernet port (Independently managed)

Communication:

  • Integrated LTE
  • Wi-Fi
  • BLE
  • USB

Interface & Services:

  • 1.47″ IPS TFT display + joystick for local setup and feedback.
  • Includes 1 GB of data (up to 500 MB LTE + 500 MB DB storage) via sensblue.cloud — no external SIM required.
  • EU-hosted servers, TLS, weekly backups, VPN on request.
  • Other versions under request.

3. Hardware Specifications

Parameter Specification
Platform Raspberry Pi Compute Module 4 (CM4)
Processor Broadcom BCM2711 Quad-core Cortex-A72 (ARM v8)
CPU Frequency 1.5 GHz
RAM 4GB LPDDR4
Storage 32 GB eMMC
Selected Variant CM4102032-4 GB RAM/ 32 GB eMMC / Wi-Fi / BLE
PCle 1 x PCle Gen 2.0 (1 lane)
HDMI 1 interfaces
USB 2 x USB 2.0

4. Power

Parameter Specification
Input voltage 12-24 VDC ± 5%
Reverse polarity protection Yes
Overcurrent protection Resettable PTC fuse
Surge protection TVS clamp for transient events
Isolation No isolation
Typical consumption < 15 W
Maximum consumption 25 W (all peripherals active)

5. Digital Inputs

Parameter Specification
Channels 4
Input voltage 0-24 VDC
Logic LOW Acording to EN 61131-2 Type I and Ill
Logic HIGH Acording to EN 61131-2 Type I and Ill
Input type Sourcing (PNP)
Input current Acording to EN 61131-2 Type I and Ill
Isolation Funcional Safety Gavanic isolation
Isolation Voltage Functional isolation between channels on the field side +- 60V
Isolation Voltage DIN VDE V 0884-11 Maximum working isolation voltage 400V RMS
Isolation Voltage DIN VDE V 0884-11 Maximum surge isolation voltage 1 kV RMS
Special feature Can be used as fast inputs until 100Hz

5.1 Wiring

6. Digital Outputs (Relay)

Parameter Specification
Channels 2
Type Mechanical relay
Switching capacity 2 A@ 30 VDC
Isolation 1000 VAC galvanic isolation
Lifetime (nominal load) ≥ 100,000 cycles
Lifetime (no load) ≥ 100,000,000 cycles

6.1 Wiring

7. Digital Outputs (Transistor/ SSR)

Parameter Specification
Channels 8
Type PNP (sourcing) SSR
Maximum current 300 mA per channel
Maximum voltage 24 VDC
Isolation Funcional Safety Gavanic isolation
Isolation Voltage DIN VDE V 0884-17 Maximum transient isolation voltage 1 kV RMS

7.1 Wiring

8. Analog Inputs

Parameter Specification
Channels 4
Mode Voltage or current configurable per channel
Voltage range 0-10 V
Current range 0/4-20 mA
ADC resolution 16 bits
ADC Sample Rate 32 samples/sec
Accuracy ≤ ±1.0% FSR
Input impedance (voltage) > 100 kΩ
Input impedance (current) 100 Ω
Protection TVS + analog filtering
Sampling rate ≥ 10 Hz per channel
Isolation Funcional Safety Gavanic isolation
Isolation Voltage Maximum transient isolation voltage 1 kV RMS

8.1 Wiring

9. Analog Outputs

Parameter Specification
Channels 2
Output type Current
Range 0-20 mA
Optional range 4-20 mA (software configurable)
Resolution 12
Accuracy ≤ ±1.0% FSR
Isolation Funcional Safety Gavanic isolation
Isolation Voltage Maximum transient isolation voltage 1 kV RMS

9.1 Wiring

10. Communication Interfaces

10.1 Ethernet

Parameter Specification
Ports 2 x RJ45
Port 1 10/100 Mbps
Port 2 0/100/1000 Mbps (native CM4)
Indicators Link + Activity LEDs

10.2 RS-485

Parameter Specification
Mode Half-duplex
Control TX_EN line
Protocol Transparent/ any
Isolation None
10.2.1 Wiring

10.3 USB

Parameter Specification
Ports 2
Type USB-A
Standard USB 2.0 Host
Maximum current 400 mA per port
Protection Overcurrent protection

10.4 HDMI

Parameter Specification
Ports 1
Connector HDMI full-size
Maximum resolution Depends on CM4 and OS

11. RF Communications

Technology Specification
Wi-Fi Integrated in CM4
BLE Integrated in CM4
LTE M.2 NGFF modem SIM7600G
SIM External access

11.1  Antenna Connectors

Connector Usage
RP-SMA Wi-Fi / BLE
SMA LTE

12. Local Peripherals

Peripheral Description
Temperature sensor Internal board temperature monitoring
Non-volatile memory Persistent storage
Security IC Microchip ATECC608A
RTC Real Time Clock with battery backup

13. HDMI

13. 1 Display

Parameter Specification 
Type IPS TFT LCD
Interface SPI
Size 1.47"
Resolution ≥ 172 X 320
Backlight LED
Mounting Front mounted with transparent window

13. 2 Joystick

Parameter Specification 
Positions 5 (Up/ Down/ Left/ Right/ Enter)
Type Mechanical tactile switch
Interface GPIO Expander

14. Mechanical

Parameter Specification 
Mounting DIN rail (EN 60715)
Enclosure MAT0091092 (same as iSense / iCee)
Protection rating IP20
Mounting method DIN rail snap-fit

15. Environmental

Parameter Specification 
Operating temperature -10 °C to +60 °C
Storage temperature -20 °C to +80 °C
Humidity 5-95% non-condensing
Vibration IEC 60068-2-6
Shock IEC 60068-2-27

16. Certifications

Certification Standard  
CE Yes
EMC 2014/30/EU
Radio 2014/53/EU (RED)
Ro HS 2011/65/EU

17. Connectivity

Parameter Specification  
Connector type Pluggable System Terminal Block
Pitch 3.5 mm
Layout Dual-row
Identification Side panel silk screen
Fixation Mechanical locking or spring clamp
Protection Mechanical reverse insertion protection

18. Expansion

Feature Description 
Piggyback area Reserved PCB area
Compatibility Fully compatible with existing FW
Power rails available Vin, 5 V, 3.3 V
Interfaces available 12C, SPI, UART, GPIO
External 1/0 lines 32 lines routed to external connectors
Storage expansion M.2 NVMe SSD connector

19. External Interfaces

Front View


Bottom View


20. Pinouts

Top View

21. System Type

Raspian

Debian GNU/Linux 13 (trixie) Version 13.2 Linux atlas 6.12.47 +rpt-rpi-v8 #1 SMP PREEMPT

Debian 1 :6.12.47-1 +rpt1 (2025-09-16) aarch64 GNU/Linux.

22. Network Information

There is three ways to connect to the device. IP and state of the connection be checked on the LCD Network Interface.

22.1 Eth1 (ethO)

Client dynamic IP obtained by DHCP server.

22.2 Eth2 (eth1)

Static IP: 93.48.86.253

22.3 Access Point (wlanO)

IP: 192.168.30.1

23. Software Information

Node-Red Grafana lnfluxDB
Version 4.1.4 12.3.1 2.8.0
Port 1880 3000 8086
State Clean Clean Clean
Authentication None User/Pass (admin/admin) Not defined, configured on first time interface login.
GUI on http://<device-ip>:1880 http://<device-ip>:3000 http://<device-ip>:8086

24. MQTT Broker

port: 1883

address: AP-> 192.168.30.1

Eth1: 93.48.86.253

user: < not needed>

login <not needed>

24.1 Relay Outputs Actor

24.1.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credentials.

a) Set/reset digital output pin/pins state

Both relays default state is open.

Req-Topic: relayOutputs/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "D01": {
        "state": "open"
      },
      "D02": {
        "state": "open"
      }
    }
  }
}

Reply-Topic: relayOutputs/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "D01": {
        "success": true,
        "state": "open"
      },
      "D02": {
        "success": true,
        "state": "open"
      }
    }
  }
}
b) Get all relays state

Req-Topic: relayOutputs/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: relayOutputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "D01": {
        "success": true,
        "state": "open"
      },
      "D02": {
        "success": true,
        "state": "close"
      }
    }
  }
}
c) Set all relays state

Req-Topic: relayOutputs/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET",
    "taskParams": {
      "D01": {
        "state": "open"
      },
      "D02": {
        "state": "close"
      }
    }
  }
}

Reply-Topic: relayOutputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "D01": {
        "success": true,
        "state": "open"
      },
      "D02": {
        "success": true,
        "state": "close"
      }
    }
  }
}

24.2 RTC Actor

24.2.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.

a) Set timer/alarm interruption

mode: Timer, alarm or none.

alarmSet: Date and time for alarm interruption (No effect if mode is timer or none).

timerSetSeconds: Period in seconds for timer interruption (No effect if mode is alarm or none).

Req-Topic: clock/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "CLOCK_SET_MODE": {
        "mode": "timer",
        "alarmSet": "[timestamp epoch ms]",
        "timerSetSeconds": "<INT>"
      }
    }
  }
}

Req-Topic: clock/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "CLOCK_SET_MODE": {
        "mode": "timer",
        "alarmSet": "[timestamp epoch ms]",
        "timerSetSeconds": "<INT>"
      }
    }
  }
}
b) Toggle RTC sync logic (described below)

tcState: State of the synchronization logic of the RTC, this value is non-persistent so every-time a reboot happens the value return to default (by default the value is ON)

Req-Topic: clock/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "TOGGLE"
  }
}

Req-Topic: clock/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "rtcState": "OFF"
    }
  }
}
c) Read clock configs

mode: Timer, alarm or none.

alarmSet: Date and time for alarm interruption (No effect if mode is timer or none).

timerSetSeconds: Period in seconds for timer interruption (No effect if mode is alarm or none).

rtcState: Current state of the synchronization logic of the RTC.

Req-Topic: clock/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: clock/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "CLOCK_CONFIGS": {
        "mode": "timer",
        "alarmSet": "[timestamp epoch ms]",
        "timerSetSeconds": "<INT>",
        "rtcState": "ON"
      }
    }
  }
}
d) Read clock

Req-Topic: clock/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "timestamp": "[timestamp epoch ms]"
    }
  }
}
24.2.2 Synchronization loop flowchart (every 30 seconds)

RTC Actor - Overview

24.3 Core System Health Actor

24.3.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker.

This interface allows any external App to receive system-level metrics such as CPU load, RAM usage, disk usage, temperature, core frequency, system throttle status and uptime.

No credentials are required to subscribe to this topic.

The System Health Actor does not receive commands. It is fully autonomous and publishes its metrics every 1 second.

24.3.2 Runtime Data

Topic: systemHealth/runtime/out

Publish rate: 1 Hz (one message per second, clock-jump safe)

a) Metrics Provided
Key Description Unit
cpu_percent Current CPU load %
cpu_tempC CPU temperature read from Linux thermal zones ºC
cpu0_freq CPU Core O current frequency Hz
cpul_freq CPU Core 1 current frequency Hz
cpu2_freq CPU Core 2 current frequency Hz
cpu3_freq CPU Core 3 current frequency Hz
cpu0_throttle System throttle status register Hex
ram_percent RAM usage %
disk_percent Disk usage for filesystem root / %
uptime_sec Time since last reboot seconds

Example Payload (systemHealth/runtime/out)

{
  "id": <TIMESTAMP>,
  "origin": "system-health",
  "task": {
    "taskResult": {
      "cpu_percent": 7.1,
      "cpu_tempC": 47.3,
      "cpu0_freq": 1500000000,
      "cpu1_freq": 1500000000,
      "cpu2_freq": 1500000000,
      "cpu3_freq": 1500000000,
      "cpu0_throttle": "0x0",
      "ram_percent": 32.9,
      "disk_percent": 41.2,
      "uptime_sec": 5321
    }
  }
}
24.3.3 Peripherals health

  In order get the peripherals health we had to implement a SystemHealth actor in each bus manager (busi2c­O, busi2c-1, etc. ... ).


a) Example

For busi2c-0:

Reply topic: systemHealth/busi2c-0/runtime/out

Payload:

{
  "id": <TIMESTAMP>,
  "origin": "system-health-busi2c-0",
  "task": {
    "taskResult": {
      "ADC": {
        "status": "ERROR",
        "description": "IRQ Retrying",
        "last_report": 1770378753006,
        "stats": {
          "AI1": {
            "samples": 563154,
            "retries": 760548,
            "discards": 253313
          },
          "AI2": {
            "samples": 563154,
            "retries": 760475,
            "discards": 253314
          },
          "AI3": {
            "samples": 563154,
            "retries": 760528,
            "discards": 253313
          },
          "AI4": {
            "samples": 563154,
            "retries": 760549,
            "discards": 253312
          }
        }
      },
      "DAC": {
        "status": "OK",
        "description": "Running....",
        "last_report": 1770378752576,
        "stats": {
          "AO1": {
            "samples": 240755,
            "retries": 0,
            "discards": 0
          },
          "AO2": {
            "samples": 240755,
            "retries": 0,
            "discards": 0
          }
        }
      },
      "RTC": {
        "status": "OK",
        "description": "",
        "last_report": 1770378752094,
        "stats": {
          "samples": 248710,
          "retries": 0,
          "discards": 0
        }
      },
      "TEMP": {
        "status": "OK",
        "description": "",
        "last_report": 1770378752579,
        "stats": {
          "samples": 240754,
          "retries": 0,
          "discards": 0
        }
      }
    }
  }
}

For busi2c-1:

Reply topic: systemHealth/busi2c-1/runtime/out

Payload:

{
  "id": <TIMESTAMP>,
  "origin": "system-health-busi2c-1",
  "task": {
    "taskResult": {
      "JOYSTICK": {
        "status": "OK",
        "description": "Running....",
        "last_report": 1770382405050,
        "stats": {
          "read_all": {
            "samples": 410154,
            "retries": 0,
            "discards": 0
          },
          "read_raw": {
            "samples": 0,
            "retries": 0,
            "discards": 0
          },
          "buttons": {
            "JDOWN": {
              "reads": 410154,
              "last_state": "pressed"
            },
            "JRIGHT": {
              "reads": 410154,
              "last_state": "pressed"
            },
            "JUP": {
              "reads": 410154,
              "last_state": "pressed"
            },
            "JLEFT": {
              "reads": 410154,
              "last_state": "pressed"
            },
            "JCENTER": {
              "reads": 410154,
              "last_state": "pressed"
            }
          }
        }
      },
      "RELAYS": {
        "status": "OK",
        "description": "Relay Output MQTT connected",
        "last_report": 1770298859099,
        "stats": {
          "read_all": {
            "samples": 0,
            "retries": 0,
            "discards": 0
          },
          "set": {
            "samples": 0,
            "retries": 0,
            "discards": 0
          },
          "set_many": {
            "samples": 0,
            "retries": 0,
            "discards": 0
          },
          "raw_read_all": {
            "samples": 0,
            "retries": 0,
            "discards": 0
          }
        },
        "outputs": {
          "DO1": {
            "writes": 0,
            "last_state": "unknown"
          },
          "DO2": {
            "writes": 0,
            "last_state": "unknown"
          }
        }
      },
      "DI": {
        "status": "OK",
        "description": "Running",
        "last_report": 1770382404832,
        "stats": {
          "read_all": {
            "samples": 181758,
            "retries": 0,
            "discards": 0
          },
          "read_raw": {
            "samples": 0,
            "retries": 0,
            "discards": 0
          },
          "inputs": {
            "DI1": {
              "reads": 181758,
              "last_state": "low"
            },
            "DI2": {
              "reads": 181758,
              "last_state": "low"
            },
            "DI3": {
              "reads": 181758,
              "last_state": "low"
            },
            "DI4": {
              "reads": 181758,
              "last_state": "low"
            }
          }
        }
      }
    }
  }
}
24.3.4 Commands
a) List usb devices

The list_usb_devices action returns a parsed list of USB devices detected on the system using the lsusb command.

Req-topic: systemHealth/runtime/in

{
"id": <TIMESTAMP>,
"origin": "Dev",
"task": {
   "action": "LIST_USB_DEVICES"
 }
}

Reply-topic: systemHealth/runtime/usb/devices/out

{
"id": <TIMESTAMP>,
"origin": "system-health",
"task": {
  "action": "list_usb_devices",
  "taskResult": {
     "usb_devices": {
       "success": true,
       "command": "lsusb",
       "returncode": 0,
       "devices": [ 
         {
           "bus": "001",
           "device": "001",
           "vendor_id": "1d6b",
           "product_id": "0002",
           "description": "Linux Foundation 2.0 root hub",
           "parsed": true
         },
         {
           "bus": "001",
           "device": "002",
           "vendor_id": "0424",
           "product_id": "9514",
           "description": "Microchip Technology, Inc. (formerly SMSC) SMC9514 Hub",
           "parsed": true
         },
         {
           "bus": "001",
           "device": "003",
           "vendor_id": "0424",
           "product_id": "ec00",
           "description": "Microchip Technology, Inc. (formerly SMSC) SMSC9512/9514 Fast Ethernet Adapter",
           "parsed": true
         },
         {
           "bus": "001",
           "device": "004",
           "vendor_id": "1e0e",
           "product_id": "9001",
           "description": "Qualcomm / Option SimTech, Incorporated",
           "parsed": true
         }
       ],
       "stderr": ""
      }
    }
  }
}
JSON Path Type Example Description
id string /number "get-hw-info-001" Request identifier echoed back in the response.
origin string "system-health" Actor/device that generated the response.
task object {...} Container for the action response.
task.action string "list_usb_devices" Action executed by the actor.
task.taskResult object {...} Main result object for the action.
task.taskResult.usb_devices object {...} Contains the USB device scan result.
task.taskResult.usb_devices.success boolean true Indicates whether the lsusb

commandexecuted successfully.

task.taskResult.usb_devices.command string "lsusb" Command used to collect USB information.
task.taskResult.usb_devices.returncode number /null 0 Process return code. 0 means success. null

means the command was not executed ortimed out.

task.taskResult.usb_devices.devices array [...] List of USB devices detected by lsusb.
task.taskResult.usb_devices.devices[ ].bus string "001" USB bus number where the device wasdetected.
task.taskResult.usb_devices.devices[ ].device string "004" USB device number assigned on that bus.
task.taskResult.usb_devices.devices[ ].vendor_id string "1e0e" USB vendor ID in hexadecimal format.
task.taskResult.usb_devices.devices[ ].product_id string "9001" USB product ID in hexadecimal format.
task.taskResult.usb_devices.devices[ ].description string "Qualcomm / Option SimTech,Incorporated" Human-readable device description returnedby lsusb.
task.taskResult.usb_devices.devices[ ].parsed boolean true Indicates whether the lsusb line was parsed successfully.
task.taskResult.usb_devices.devices[ ].raw string Optional Present only when a device line could not beparsed.

Contains the original raw lsusb line.

task.taskResult.usb_devices.stderr string " " Error output from the command. Empty stringmeans no error.
b) List connectivity specs

The list_connectivity_specs action allows the SystemHealth Actor to return connectivity information for the device, including the status of:

  • Wi-Fi
  • LTE modem
  • eth0
  • eth1
  • Tunnel interfaces, for possible commissioning use

Req-topic: systemHealth/runtime/in

{
"id": "connectivity-001",
"origin": "APP",
"task": {
  "action": "list_connectivity_specs"
 }
}

Reply-topic: systemHealth/runtime/connectivity/out

{
  "id": "<TIMESTAMP>",
  "origin": "system-health",
  "task": {
    "action": "list_connectivity_specs",
    "taskResult": {
      "connectivity": {
        "sources": {
          "sysfs": "/sys/class/net",
          "ip_link": {
            "available": true,
            "command": "ip -j -d link show",
            "error": null
          },
          "network_manager": {
            "available": true,
            "command": "nmcli -t -f DEVICE,TYPE,STATE,CONNECTION device status",
            "error": null
          }
        },
        "interfaces": {
          "wifi": {
            "available": true,
            "interfaces": [
              {
                "interface": "wlan0",
                "available": true,
                "status": "down",
                "operstate": "down",
                "admin_up": true,
                "carrier": false,
                "mtu": 1500,
                "type": 1,
                "link_kind": null,
                "mac_address": "2c:cf:67:fd:60:40",
                "ipv4": [],
                "ipv6": [],
                "network_manager": {
                  "device": "wlan0",
                  "type": "wifi",
                  "state": "disconnected",
                  "connection": null
                },
                "wifi": {
                  "available": true,
                  "command": "iw dev wlan0 link",
                  "connected": false
                }
              }
            ]
          },
          "lte_modem": {
            "available": true,
            "tool_available": true,
            "command": "mmcli -L",
            "modems": [
              {
                "id": "0",
                "success": true,
                "command": "mmcli -m 0 --output-json",
                "manufacturer": "QUALCOMM INCORPORATED",
                "model": "SIMCOM_SIM7600G-H",
                "revision": "LE20B04SIM7600G22",
                "hardware_revision": "10000",
                "device": "/sys/devices/platform/scb/fe9c0000.xhci/usb1/1-1/1-1.4",
                "drivers": [
                  "qmi_wwan",
                  "option"
                ],
                "plugin": "simtech",
                "primary_port": "cdc-wdm0",
                "ports": [
                  {
                    "name": "cdc-wdm0",
                    "type": "qmi"
                  },
                  {
                    "name": "ttyUSB0",
                    "type": "ignored"
                  },
                  {
                    "name": "ttyUSB1",
                    "type": "gps"
                  },
                  {
                    "name": "ttyUSB2",
                    "type": "at"
                  },
                  {
                    "name": "ttyUSB3",
                    "type": "at"
                  },
                  {
                    "name": "ttyUSB4",
                    "type": "audio"
                  },
                  {
                    "name": "wwan0",
                    "type": "net"
                  }
                ],
                "state": "failed",
                "power_state": "on",
                "access_technologies": [],
                "signal_quality": {
                  "recent": "yes",
                  "value": "0"
                },
                "current_capabilities": [
                  "gsm-umts, lte"
                ],
                "supported_capabilities": [
                  "gsm-umts, lte"
                ],
                "operator_code": "--",
                "operator_name": "--",
                "registration_state": "--",
                "packet_service_state": "--",
                "sim_path": null
              }
            ],
            "network_interfaces": [
              {
                "interface": "wwan0",
                "available": true,
                "status": "down",
                "operstate": "down",
                "admin_up": false,
                "carrier": null,
                "mtu": 1500,
                "type": 65534,
                "link_kind": null,
                "mac_address": null,
                "ipv4": [],
                "ipv6": [],
                "network_manager": null
              }
            ]
          },
          "eth0": {
            "interface": "eth0",
            "available": true,
            "status": "connected",
            "operstate": "up",
            "admin_up": true,
            "carrier": true,
            "mtu": 1500,
            "type": 1,
            "link_kind": null,
            "mac_address": "2c:cf:67:fd:60:3f",
            "ipv4": [
              {
                "address": "172.16.20.57",
                "prefixlen": 24,
                "scope": "global",
                "dynamic": true
              }
            ],
            "ipv6": [
              {
                "address": "fe80::7fc1:f65f:5729:d234",
                "prefixlen": 64,
                "scope": "link",
                "dynamic": false
              }
            ],
            "network_manager": {
              "device": "eth0",
              "type": "ethernet",
              "state": "connected",
              "connection": "wired-ip-dynamic"
            }
          },
          "eth1": {
            "interface": "eth1",
            "available": true,
            "status": "unavailable",
            "operstate": "down",
            "admin_up": true,
            "carrier": false,
            "mtu": 1500,
            "type": 1,
            "link_kind": null,
            "mac_address": "2c:cf:67:fd:60:41",
            "ipv4": [],
            "ipv6": [],
            "network_manager": {
              "device": "eth1",
              "type": "ethernet",
              "state": "unavailable",
              "connection": null
            }
          },
          "tunnel": {
            "available": false,
            "interfaces": []
          }
        }
      }
    }
  }
}
Field Type Description
id string/number Request/response identifier used to correlate therequest with the response.
origin string Origin of the message. In the response, this is normallythe SystemHealth actor name.
task.action string Executed action. For this feature, the value is list_connectivity_specs.
task.taskResult.connectivity.sources.sysfs string Linux sysfs path used to discover network interfaces, usually/sys/class/net.
task.taskResult.connectivity.sources.ip_link.available boolean Indicates whether the ip command was available andexecuted successfully.
task.taskResult.connectivity.sources.ip_link.command string Command used to retrieve detailed link information,for example ip -j -d link show.
task.taskResult.connectivity.sources.ip_link.error string/null Error returned by the ip command, or null if no erroroccurred.
task.taskResult.connectivity.sources.network_manager.available boolean Indicates whether NetworkManager / nmcli was available and executed successfully.
task.taskResult.connectivity.sources.network_manager.command string Command used to retrieve NetworkManager device status.
task.taskResult.connectivity.sources.network_manager.error string/null Error returned by nmcli, or null if no error occurred.
task.taskResult.connectivity.interfaces.wifi.available boolean Indicates whether at least one Wi-Fi interface was found.
task.taskResult.connectivity.interfaces.wifi.interfaces[ ] array List of detected Wi-Fi interfaces, usually including wlan0 when Wi-Fi exists.
wifi.interfaces[ ].interface string Linux interface name, for example wlan0.
wifi.interfaces[ ].available boolean Indicates whether the Wi-Fi interface exists in the system.
wifi.interfaces[ ].status string Normalized interface status, for example connected, down, unavailable, no_carrier, or not_available.
wifi.interfaces[ ].operstate string / null Operational state reported by Linux, for example up, down, or unknown.
wifi.interfaces[ ].admin_up boolean / null Indicates whether the interface is administratively enabled.
wifi.interfaces[ ].carrier boolean / null Indicates whether carrier/link is detected.
wifi.interfaces[ ].mtu number / null Maximum Transmission Unit of the interface.
wifi.interfaces[ ].type number / null Linux interface type.
wifi.interfaces[ ].link_kind string / null Special link type, used mainly for virtual/tunnel interfaces. Usually null for normal Wi-Fi.
wifi.interfaces[ ].mac_address string / null MAC address of the Wi-Fi interface.
wifi.interfaces[ ].ipv4[ ] array List of IPv4 addresses configured on the Wi-Fi interface.
wifi.interfaces[ ].ipv6[ ] array List of IPv6 addresses configured on the Wi-Fi interface.
wifi.interfaces[ ].network_manager.device string NetworkManager device name.
wifi.interfaces[ ].network_manager.type string NetworkManager interface type, usually wifi.
wifi.interfaces[ ].network_manager.state string NetworkManager state, for example connected, disconnected, or unavailable.
wifi.interfaces[ ].network_manager.connection string / null Active NetworkManager profile name, or null if none is active.
wifi.interfaces[ ].wifi.available boolean Indicates whether Wi-Fi details could be queried using iw.
wifi.interfaces[ ].wifi.command string Command used to query Wi-Fi link state, for example iw dev wlan0 link.
wifi.interfaces[ ].wifi.connected boolean / null Indicates whether the Wi-Fi interface is associated with a Wi-Fi network.
wifi.interfaces[ ].wifi.ssid string SSID of the connected Wi-Fi network, when connected.
wifi.interfaces[ ].wifi.bssid string BSSID/MAC address of the connected access point, when connected.
wifi.interfaces[ ].wifi.frequency_mhz number Wi-Fi frequency in MHz, when connected.
wifi.interfaces[ ].wifi.signal_dbm number Wi-Fi signal strength in dBm, when available.
wifi.interfaces[ ].wifi.tx_bitrate string Wi-Fi transmit bitrate, when available.
wifi.interfaces[ ].wifi.rx_bitrate string Wi-Fi receive bitrate, when available.
task.taskResult.connectivity.interfaces.lte_modem.available boolean Indicates whether at least one LTE modem was detected.
task.taskResult.connectivity.interfaces.lte_modem.tool_available boolean Indicates whether mmcli / ModemManager is available.
task.taskResult.connectivity.interfaces.lte_modem.command string Command used to list LTE modems, usually mmcli -L.
task.taskResult.connectivity.interfaces.lte_modem.modems[ ] array List of LTE modems detected by ModemManager.
lte_modem.modems[ ].id string Modem ID in ModemManager, for example 0.
lte_modem.modems[ ].success boolean Indicates whether detailed modem information wasread successfully.
lte_modem.modems[ ].command string Command used to read modem details, for example mmcli -m 0 --output-json.
lte_modem.modems[ ].manufacturer string / null Modem manufacturer.
lte_modem.modems[ ].model string / null Modem model.
lte_modem.modems[ ].revision string / null Modem firmware/software revision.
lte_modem.modems[ ].hardware_revision string / null Modem hardware revision.
lte_modem.modems[ ].device string / null Sysfs/USB path of the modem device.
lte_modem.modems[ ].drivers[ ] array Linux drivers associated with the modem, for example qmi_wwan or option.
lte_modem.modems[ ].plugin string / null ModemManager plugin used to manage the modem.
lte_modem.modems[ ].primary_port string / null Primary modem control port, for example cdc-wdm0.
lte_modem.modems[ ].ports[ ] array List of ports associated with the modem.
lte_modem.modems[ ].ports[ ].name string Port/interface name, for example cdc-wdm0, ttyUSB2, or wwan0.
lte_modem.modems[ ].ports[ ].type string / null Port type, for example qmi, at, gps, audio, net, or ignored.
lte_modem.modems[ ].state string / null General modem state according to ModemManager,for example registered, connected, or failed.
lte_modem.modems[ ].power_state string / null Modem power state, for example on, off, or low.
lte_modem.modems[ ].access_technologies[ ] array Current access technologies in use, for example LTE,UMTS, or GSM.
lte_modem.modems[ ].signal_quality.recent string / null Indicates whether the signal quality value is recent.
lte_modem.modems[ ].signal_quality.value string / number / null Signal quality value reported by the modem.
lte_modem.modems[ ].current_capabilities[ ] array Current modem capabilities.
lte_modem.modems[ ].supported_capabilities[ ] array Capabilities supported by the modem.
lte_modem.modems[ ].operator_code string / null MCC/MNC operator code.
lte_modem.modems[ ].operator_name string / null Operator name.
lte_modem.modems[ ].registration_state string / null Mobile network registration state.
lte_modem.modems[ ].packet_service_state string / null Mobile packet data service state.
lte_modem.modems[ ].sim_path string / null SIM path in ModemManager, when available.
task.taskResult.connectivity.interfaces.lte_modem.network_interfaces[] array List of Linux network interfaces associated with the LTE modem, usually wwan0.
lte_modem.network_interfaces[ ].interface string LTE network interface name, for example wwan0.
lte_modem.network_interfaces[ ].available boolean Indicates whether the LTE network interface exists.
lte_modem.network_interfaces[ ].status string Normalized LTE network interface status.
lte_modem.network_interfaces[ ].operstate string / null Operational state reported by Linux.
lte_modem.network_interfaces[ ].admin_up boolean / null Indicates whether the LTE network interface is administratively enabled.
lte_modem.network_interfaces[ ].carrier boolean / null Indicates whether carrier/link information is availableand active.
lte_modem.network_interfaces[ ].mtu number / null Maximum Transmission Unit of the LTE network interface.
lte_modem.network_interfaces[ ].type number / null Linux interface type.
lte_modem.network_interfaces[ ].link_kind string / null Link kind, when available.
lte_modem.network_interfaces[ ].mac_address string / null MAC address, when available.
lte_modem.network_interfaces[ ].ipv4[ ] array IPv4 addresses configured on the LTE network interface.
lte_modem.network_interfaces[ ].ipv6[ ] array IPv6 addresses configured on the LTE network interface.
lte_modem.network_interfaces[ ].network_manager object / null NetworkManager information for the LTE interface, when available.
task.taskResult.connectivity.interfaces.eth0.interface string Ethernet interface name, eth0.
task.taskResult.connectivity.interfaces.eth0.available boolean Indicates whether eth0 exists.
task.taskResult.connectivity.interfaces.eth0.status string Normalized eth0 status.
task.taskResult.connectivity.interfaces.eth0.operstate string / null Operational state of eth0.
task.taskResult.connectivity.interfaces.eth0.admin_up boolean / null Indicates whether eth0 is administratively enabled.
task.taskResult.connectivity.interfaces.eth0.carrier boolean / null Indicates whether eth0 has physical link.
task.taskResult.connectivity.interfaces.eth0.mtu number / null MTU of eth0.
task.taskResult.connectivity.interfaces.eth0.type number / null Linux interface type of eth0.
task.taskResult.connectivity.interfaces.eth0.link_kind string / null Link kind of eth0, usually null.
task.taskResult.connectivity.interfaces.eth0.mac_address string / null MAC address of eth0.
task.taskResult.connectivity.interfaces.eth0.ipv4[ ] array IPv4 addresses configured on eth0.
task.taskResult.connectivity.interfaces.eth0.ipv6[ ] array IPv6 addresses configured on eth0.
task.taskResult.connectivity.interfaces.eth0.network_manager object / null NetworkManager information for eth0.
task.taskResult.connectivity.interfaces.eth1.interface string Ethernet interface name, eth1.
task.taskResult.connectivity.interfaces.eth1.available boolean Indicates whether eth1 exists.
task.taskResult.connectivity.interfaces.eth1.status string Normalized eth1 status.
task.taskResult.connectivity.interfaces.eth1.operstate string / null Operational state of eth1.
task.taskResult.connectivity.interfaces.eth1.admin_up boolean / null Indicates whether eth1 is administratively enabled.
task.taskResult.connectivity.interfaces.eth1.carrier boolean / null Indicates whether eth1 has physical link.
task.taskResult.connectivity.interfaces.eth1.mtu number / null MTU of eth1.
task.taskResult.connectivity.interfaces.eth1.type number / null Linux interface type of eth1.
task.taskResult.connectivity.interfaces.eth1.link_kind string / null Link kind of eth1, usually null.
task.taskResult.connectivity.interfaces.eth1.mac_address string / null MAC address of eth1.
task.taskResult.connectivity.interfaces.eth1.ipv4[ ] array IPv4 addresses configured on eth1.
task.taskResult.connectivity.interfaces.eth1.ipv6[ ] array IPv6 addresses configured on eth1.
task.taskResult.connectivity.interfaces.eth1.network_manager object / null NetworkManager information for eth1.
task.taskResult.connectivity.interfaces.tunnel.available boolean Indicates whether at least one tunnel interface was detected.
task.taskResult.connectivity.interfaces.tunnel.interfaces[ ] array List of detected tunnel interfaces, for example tun0, tap0, wg0, or tailscale0.
tunnel.interfaces[ ].interface string Tunnel interface name.
tunnel.interfaces[ ].available boolean Indicates whether the tunnel interface exists.
tunnel.interfaces[ ].status string Normalized tunnel interface status.
tunnel.interfaces[ ].operstate string / null Operational state reported by Linux.
tunnel.interfaces[ ].admin_up boolean / null Indicates whether the tunnel interface isadministratively enabled.
tunnel.interfaces[ ].carrier boolean / null Carrier/link information, when available.
tunnel.interfaces[ ].mtu number / null Tunnel interface MTU.
tunnel.interfaces[ ].type number / null Linux interface type.
tunnel.interfaces[ ].link_kind string / null Tunnel link kind, for example tun, tap, or wireguard.
tunnel.interfaces[ ].mac_address string / null MAC address, when available.
tunnel.interfaces[ ].ipv4[ ] array IPv4 addresses configured on the tunnel interface.
tunnel.interfaces[ ].ipv6[ ] array IPv6 addresses configured on the tunnel interface.
tunnel.interfaces[ ].network_manager object / null NetworkManager information for the tunnel interface, when available.
ipv4[ ].address string IPv4 address assigned to the interface.
ipv4[ ].prefixlen number IPv4 network prefix length. Example: 24.
ipv4[ ].scope string IPv4 scope, for example global.
ipv4[ ].dynamic boolean Indicates whether the IPv4 address was dynamically assigned.
ipv6[ ].address string IPv6 address assigned to the interface.
ipv6[ ].prefixlen number IPv6 network prefix length.
ipv6[ ].scope string IPv6 scope, for example link or global.
ipv6[].dynamic boolean Indicates whether the IPv6 address was dynamically assigned.
c) Get hardware info

Req-topic: systemHealth/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "Dev",
  "task": {
    "action": "GET_HW_INFO"
  }
}

Reply-topic: systemHealth/runtime/hw/info/out

{
  "id": "<TIMESTAMP>",
  "origin": "system-health",
  "task": {
    "action": "get_hw_info",
    "taskResult": {
      "cpu": {......},
      "ram": {......},
      "emmc": {......},
      "block_devices": {......},
      "filesystems": {......},
      "mmc_sysfs": {......},
      "emmc_extcsd": {......}
    }
  }
}
Section Description
cpu CPU and board model information.
ram RAM total, used, and free memory.
emmc Filtered eMMC device and partition information.
block_devices Complete block device list from lsblk, including eMMC, boot partitions, loop devices, zram, NVMe, USB storage, etc.
filesystems Mounted filesystem usage from df -h.
mmc_sysfs Low-level MMC/eMMC identity fields read from /sys/block/mmcblk*/device.
emmc_extcsd Parsed eMMC EXT_CSD information from mmc extcsd read, including health, revision, RPMB, boot, and partitioning data.
  • CPU

The cpu object describes the detected board and CPU.

{
  "board_model": "Raspberry Pi Compute Module 4 Rev 1.1",
  "cpu": {
    "architecture": "aarch64",
    "op_modes": "32-bit, 64-bit",
    "byte_order": "Little Endian",
    "vendor": "ARM",
    "model_name": "Cortex-A72",
    "model": "3",
    "stepping": "r0p3",
    "cpu_count": 4,
    "online_cpus": "0-3",
    "threads_per_core": 1,
    "cores_per_cluster": 4,
    "clusters": 1,
    "frequency": {
      "scaling_percent": 60.0,
      "min_mhz": 600.0,
      "max_mhz": 1500.0,
      "bogomips": 108.0
    }
  }
}
Field Type Description
board_model string / null Hardware board model read from device-tree.
cpu.architecture string CPU architecture, for example aarch64.
cpu.op_modes string Supported CPU operation modes.
cpu.byte_order string CPU byte order.
cpu.vendor string CPU vendor.
cpu.model_name string CPU model name.
cpu.model string / number CPU model identifier.
cpu.stepping string CPU stepping/revision.
cpu.cpu_count number Number of detected CPU cores.
cpu.online_cpus string Online CPU list.
cpu.threads_per_core number Number of threads per core.
cpu.cores_per_cluster number Number of cores per cluster.
cpu.clusters number Number of CPU clusters.
cpu.frequency.scaling_percent number / null Current CPU frequency scaling percentage.
cpu.frequency.min_mhz number / null Minimum CPU frequency in MHz.
cpu.frequency.max_mhz number / null Maximum CPU frequency in MHz.
cpu.frequency.bogomips number / null BogoMIPS value reported by the system.
  • RAM

The ram object reports system memory usage.

Field Type Description
total string Total system RAM.
used string Currently used RAM.
free string Currently free RAM.
  • EMMC

The emmc object is a filtered eMMC view. It focuses on the main eMMC disk and its partitions.

{
  "devices": [
    {
      "name": "mmcblk0",
      "model": null,
      "serial": "0x121b491e",
      "size": "29.1G",
      "type": "disk",
      "transport": "mmc",
      "filesystem": null,
      "mountpoints": [],
      "partitions": [
        {
          "name": "mmcblk0p1",
          "size": "512M",
          "type": "part",
          "filesystem": "vfat",
          "mountpoints": [
            "/boot/firmware"
          ]
        },
        {
          "name": "mmcblk0p2",
          "size": "28.6G",
          "type": "part",
          "filesystem": "ext4",
          "mountpoints": [
            "/"
          ]
        }
      ]
    }
  ]
}

Device fields

Field Type Description
devices[ ] array List of detected main eMMC devices.
devices[ ].serial string / null eMMC block device name, for example mmcblk0.
devices[ ].size string Device model, when available.
devices[ ].type string Device serial number.
devices[ ].transport string / null Device size.
devices[ ].filesystem string / null Device type, usually disk.
devices[ ].mountpoints array Transport type, usually mmc.
devices[ ].partitions array Filesystem directly on the disk. Usually null when partitions exist.
devices[ ].name string Mountpoints directly associated with the disk.
devices[ ].model string / null Partitions belonging to this eMMC disk.

Partition fields

Field Type Description
name string Partition name, for example mmcblk0p1.
size string Partition size.
type string Partition type, usually part.
filesystem string / null Filesystem type, for example vfat or ext4.
mountpoints array Mountpoints for the partition.
d) block_devices

The block_devices object is the complete storage/device tree returned by lsblk.

{
  "devices": [
    {
      "name": "mmcblk0",
      "model": null,
      "serial": "0x121b491e",
      "size": "29.1G",
      "type": "disk",
      "transport": "mmc",
      "filesystem": null,
      "mountpoints": [],
      "children": [
        {
          "name": "mmcblk0p1",
          "model": null,
          "serial": null,
          "size": "512M",
          "type": "part",
          "transport": "mmc",
          "filesystem": "vfat",
          "mountpoints": [
            "/boot/firmware"
          ],
          "children": []
        }
      ]
    }
  ],
  "stderr": ""
}
Field Type Description
devices array List of block devices.
stderr string Command error output, if any.
devices[index].name string Device name.
devices[index].model string / null Device model.
devices[index].serial string / null Device serial number.
devices[index].size string Device size.
devices[index].type string Device type, for example disk , part , or loop.
devices[index].transport string / null Transport type, for example mmc , nvme , or usb.
devices[index].filesystem string / null Filesystem type, for example ext4 , vfat , or swap.
devices[index].mountpoints array List of mountpoints. Empty if not mounted.
devices[index].children array Child block devices, usually partitions.
e) file_systems

The file_systems object reports mounted filesystem usage, equivalent to df -h.

{
  "filesystems": [
    {
      "source": "/dev/mmcblk0p2",
      "filesystem": "ext4",
      "size": "29G",
      "used": "5.8G",
      "available": "23G",
      "use_percent": "21%",
      "mountpoint": "/",
      "parsed": true
    },
    {
      "source": "/dev/nvme0n1p1",
      "filesystem": "ext4",
      "size": "234G",
      "used": "2.1M",
      "available": "222G",
      "use_percent": "1%",
      "mountpoint": "/mnt/nvme",
      "parsed": true
    }
  ],
  "stderr": ""
}
Field Type Description
filesystems array List of mounted filesystems.
stderr string Command error output, if any.
filesystems[index].source string Filesystem source, for example /dev/mmcblk0p2 , tmpfs , or udev.
filesystems[index].filesystem string Filesystem type, for example ext4 , vfat , tmpfs , or devtmpfs.
filesystems[index].size string Total filesystem size.
filesystems[index].used string Used space.
filesystems[index].available string Available space.
filesystems[index].use_percent string Used percentage.
filesystems[index].mountpoint string Mount location.
filesystems[index].parsed boolean true if the parser successfully parsed this filesystem entry.
f) mmc_sysfs

The mmc_sysfs object exposes low-level MMC/eMMC identity fields read from:

/sys/block/mmcblk*/device/

This is useful for production traceability, device identification and diagnostics.

{
  "source": "/sys/block",
  "fields": [
    "name",
    "cid",
    "csd",
    "date",
    "manfid",
    "oemid",
    "serial"
  ],
  "devices": [
    {
      "device": "mmcblk0",
      "base_path": "/sys/block/mmcblk0/device",
      "available": true,
      "fields": {
        "name": "BJTD4R",
        "cid": "150100424a5444345203121b491e7b00",
        "csd": "d02701320f5903fff6dbffef8e404000",
        "date": "07/2024",
        "manfid": "0x000015",
        "oemid": "0x0100",
        "serial": "0x121b491e"
      }
    }
  ]
}
Field Type Description
source string Base sysfs source path.
fields array List of sysfs fields collected.
devices array List of detected MMC/eMMC devices.
devices[index].device string MMC block device name, for example mmcblk0.
devices[index].base_path string Sysfs path used for this device.
devices[index].available boolean Indicates whether the sysfs path exists.
devices[index].fields.name string / null eMMC product name.
devices[index].fields.cid string / null Card Identification register.
devices[index].fields.csd string / null Card Specific Data register.
devices[index].fields.date string / null Manufacturing date.
devices[index].fields.manfid string / null Manufacturer ID.
devices[index].fields.oemid string / null OEM/application ID.
devices[index].fields.serial string / null eMMC serial number.
e) emmc_extcsd

The emmc_extcsd object contains parsed information from:

mmc extcsd read /dev/mmcblk0

Category Description
revision EXT_CSD and MMC version.
health eMMC lifetime and pre-EOL state.
boot Boot partition/protection configuration.
rpmb Replay Protected Memory Block information.
sector Sector count and capacity information, when available.
partitioning Partitioning and enhanced-area information.

emmc_extcsd.devices[ ].revision

{
  "ext_csd_revision": "1.8",
  "mmc_version": "MMC 5.1"
}
Field Type Description
ext_csd_revision string EXT_CSD revision.
mmc_version string MMC/eMMC standard version.

emmc_extcsd.devices[ ].health

{
  "life_time_estimation_a": {
    "field": {
      "register": "DEVICE_LIFE_TIME_EST_TYP_A",
      "index": null,
      "description": "eMMC Life Time Estimation A",
      "value": "0x01",
      "value_int": 1,
      "value_hex": "0x1"
    },
    "decoded": {
      "state": "normal",
      "used_percent_min": 0,
      "used_percent_max": 10
    }
  },
  "life_time_estimation_b": {
    "field": {
      "register": "DEVICE_LIFE_TIME_EST_TYP_B",
      "index": null,
      "description": "eMMC Life Time Estimation B",
      "value": "0x01",
      "value_int": 1,
      "value_hex": "0x1"
    },
    "decoded": {
      "state": "normal",
      "used_percent_min": 0,
      "used_percent_max": 10
    }
  },
  "pre_eol": {
    "field": {
      "register": "PRE_EOL_INFO",
      "index": null,
      "description": "eMMC Pre EOL information",
      "value": "0x01",
      "value_int": 1,
      "value_hex": "0x1"
    },
    "decoded": {
      "state": "normal"
    }
  }
}
Field Description
life_time_estimation_a Wear estimation for eMMC memory type A.
life_time_estimation_b Wear estimation for eMMC memory type B.
pre_eol Pre-end-of-life state.

Lifetime Decoding

Raw Value Decoded State Meaning
0x00 not_defined Not defined by device.
0x01 normal 0% to 10% estimated lifetime used.
0x02 normal 10% to 20% estimated lifetime used.
0x03 normal 20% to 30% estimated lifetime used.
0x04 normal 30% to 40% estimated lifetime used.
0x05 normal 40% to 50% estimated lifetime used.
0x06 normal 50% to 60% estimated lifetime used
0x07 normal 60% to 70% estimated lifetime used.
0x08 normal 70% to 80% estimated lifetime used.
0x09 normal 80% to 90% estimated lifetime used.
0x0A normal 90% to 100% estimated lifetime used.
0x0B exceeded Estimated maximum lifetime exceeded.

Pre-EOL Decoding

Raw Value Decoded State Meaning
0x00 not_defined Not defined.
0x01 normal Normal condition.
0x02 warning Warning state. Monitor or plan replacement.
0x03 urgent Urgent state. Replacement recommended.

emmc_extcsd.devices[ ].boot

{
  "partition_config": {
    "field": null,
    "decoded": null
  },
  "boot_config_protection": null,
  "boot_bus_conditions": null,
  "boot_write_protection": {
    "register": "BOOT_WP",
    "index": null,
    "description": "Boot Area Write protection",
    "value": "0x00",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "boot_size": {
    "field": null,
    "decoded": null
  }
}
Field Type Description
partition_config object / null Boot partition configuration, if available.
boot_config_protection object / null Boot configuration protection status.
boot_bus_conditions object / null Boot bus width/mode conditions.
boot_write_protection object / null Boot area write protection status.
boot_size object / null Boot partition size, if available.

emmc_extcsd.devices[ ].rpmb

RPMB means Replay Protected Memory Block. It is a protected eMMC area often used for secure storage.

{
  "size": {
    "field": {
      "register": "RPMB_SIZE_MULT",
      "index": null,
      "description": "RPMB Size",
      "value": "0x20",
      "value_int": 32,
      "value_hex": "0x20"
    },
    "decoded": {
      "bytes": 4194304,
      "kb": 4194.3,
      "mb": 4.19,
      "gb": 0.0,
      "kib": 4096.0,
      "mib": 4.0,
      "gib": 0.0
    }
  }
}
Field Type Description
size.field object / null Raw RPMB size register information.
size.decoded.bytes number RPMB size in bytes.
size.decoded.kb number RPMB size in decimal KB.
size.decoded.mb number RPMB size in decimal MB.
size.decoded.gb number RPMB size in decimal GB.
size.decoded.kib number RPMB size in KiB.
size.decoded.mib number RPMB size in MiB.
size.decoded.gib number RPMB size in GiB.

emmc_extcsd.devices[ ].sector

{
  "sector_count": null,
  "sector_size_bytes": 512,
  "user_capacity": null
}
Field Type Description
sector_count object / null Parsed sector count register, if available.
sector_size_bytes number Sector size used for capacity calculation.
user_capacity object / null Calculated user capacity, if sector count is available.

emmc_extcsd.devices[ ].partitioning

{
  "partitioning_support": {
    "register": "PARTITIONING_SUPPORT",
    "index": null,
    "description": "Partitioning Support",
    "value": "0x07",
    "value_int": 7,
    "value_hex": "0x7"
  },
  "partition_setting_completed": {
    "register": "PARTITION_SETTING_COMPLETED",
    "index": null,
    "description": "Partitioning Setting",
    "value": "0x00",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "partition_attribute": {
    "register": "PARTITIONS_ATTRIBUTE",
    "index": null,
    "description": "Partitions attribute",
    "value": "0x00",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "max_enhanced_area_size": {
    "register": "MAX_ENH_SIZE_MULT",
    "index": null,
    "description": "Max Enhanced Area Size",
    "value": "0x000747",
    "value_int": 1863,
    "value_hex": "0x747"
  },
  "enhanced_user_area_start": {
    "register": "ENH_START_ADDR",
    "index": null,
    "description": "Enhanced User Data Start Address",
    "value": "0x00000000",
    "value_int": 0,
    "value_hex": "0x0"
  },
  "enhanced_user_area_size": {
    "register": "ENH_SIZE_MULT",
    "index": null,
    "description": "Enhanced User Data Area Size",
    "value": "0x000000",
    "value_int": 0,
    "value_hex": "0x0"
  }
}
Field Type Description
partitioning_support object / null Supported partitioning features.
partition_setting_completed object / null Indicates whether partition settings were finalized.
user_capacity object / null Partition attribute register.
max_enhanced_area_size object / null Maximum enhanced area size multiplier.
enhanced_user_area_start object / null Enhanced user data area start address.
enhanced_user_area_size object / null Enhanced user data area size.

24.4 TempSensor Actor

24.4.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.

a) Set temperature sensor configurations

Req-Topic: tempSensor/config/in

ALERT:

  • activate: true(active)/false
  • templow: alert temperature lower limit
  • tempHigh: alert temperature upper limit
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "ALERT": {
        "activate": true,
        "tempLow": 0,
        "tempHigh": 80
      }
    }
  }
}

Reply-Topic: tempSensor/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "ALERT": {
        "activate": true,
        "tempLow": 0,
        "tempHigh": 80
      }
    }
  }
}
b) Read temperature sensor configurations

Req-Topic: tempSensor/config/in

ALERT:

  • activate: true(active)/false

LIMITS:

  • templow: alert temperature lower limit
  • tempHigh: alert temperature upper limit
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: tempSensor/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "ALERT": {
        "activate": true,
        "tempLow": 0,
        "tempHigh": 80
      }
    }
  }
}
c) Read temperature and alert status
  • unit: Temperature unit of measure
  • alert: true (triggered) or false

Req-Topic: tempSensor/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: tempSensor/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true,
      "data": {
        "temperature": <_FLOAT_>,
        "unit": "C",
        "alert": true
      }
    }
  }
}

24.5 TFT Actor

24.5.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to control and interact with the TFT display, or frontal panel LCD screen. Connecting to the broker for this Area requires no credentials.

24.5.2 TFT Display Actor

  The TFT Actor is responsible for:

  • Rendering static and informative screens on the TFT display
  • Reacting to joystick input (LEFT/ RIGHT/ CENTER/ UP/ DOWN)
  • Managing screen navigation and user confirmation flows
  • Providing feedback to the application via MQTT

The TFT actor maintains an ordered list of screens (carousel).

  • Screens are navigated using the joystick:

- LEFT --> Previous screen

- RIGHT --> Next screen

  • The carousel wraps around:

- LEFT on first screen --> last screen

- RIGHT on last screen --> first screen

b) Screen Types

The TFT actor supports the following screen types:

Image Screen

  • Displays a static JPEG image
  • Default screen shown at boot
  • No user interaction required

Network Information Screen

  • Display a interface with information about the networks of the device
  • Updated on load
  • No user interaction required
c) Joystick Navigation Logic

Carousel Navigation:

Joystick Input Action
LEFT Previous screen
RIGHT Next screen
DOWN Refresh current screen
d) Boot Behavior

At system boot:

  1. TFT actor initializes the display
  2. Last available carousel is loaded
  3. First screen is rendered
  4. Joystick subscriptions are activated
  5. Actor waits for runtime commands
e) Design Notes & Constraints
  • TFT actor does not expose joystick state
  • Joystick actor remains independent
  • TFT actor internally consumes joystick events
  • Carousel state is local to the TFT actor
  • Screen rendering is synchronous; input handling is asynchronous
  • Confirmation screens always require explicit CENTER press
24.5.3 User interaction through MQTT

Enabling interaction with the carousel using the topic tft/runtime/in . Actions available will be public to the user.

Runtime commands

Go to screen

Req-Topic: tft/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_CAROUSEL",
    "params": {
      "index": 2
    }
  }
}

Reply-Topic: tft/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "tft",
  "task": {
    "taskResult": {
      "success": true,
      "index": 2
    }
  }
}

Set TFT Screen Carousel Req-Topic: tft/runtime/in

{
  "id": "TIMESTAMP",
  "origin": "APP",
  "task": {
    "action": "SET_CAROUSEL",
    "params": {
      "startIndex": 0,
      "screens": [
        {
          "type": "image",
          "image": "default.jpg"
        },
        {
          "type": "image",
          "image": "status.jpg"
        },
        {
          "type": "confirm",
          "question": "Do you want to continue?"
        }
      ]
    }
  }
}

Parameters:

Field Description
screens Ordered list of screens
Start lndex Initial active screen (optional, default = 0)

Reply

Reply-Topic: tft/runtime/out

{
  "id": "TIMESTAMP",
  "origin": "tft",
  "task": {
    "taskResult": {
      "success": true,
      "activeIndex": 0,
      "totalScreens": 3
    }
  }
}

24.6 AnalogInputs Actor

24.6.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.

a) Configurations

  Topic: analogInputs/config/in - Set ADC channels configurations

mode

  • continuous
  • single

type

  • voltage
  • current
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AI1": {
        "mode": "single",
        "type": "voltage"
      },
      "AI2": {
        "mode": "single",
        "type": "voltage"
      },
      "AI3": {
        "mode": "single",
        "type": "current"
      },
      "AI4": {
        "mode": "single",
        "type": "current"
      }
    }
  }
}

Reply-Topic: analogInputs/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AI1": {
        "success": true
      },
      "AI2": {
        "success": true
      },
      "AI3": {
        "success": true
      },
      "AI4": {
        "success": true
      }
    }
  }
}
b) Runtime Data

Topic: analogInputs/runtime/in.

action:

  • READ
  • PAUSE (only applicable in continuous mode)
  • RESUME (only applicable in continuous mode)
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AI1": {
        "action": "READ"
      },
      "AI2": {
        "action": "READ"
      },
      "AI3": {
        "action": "READ"
      },
      "AI4": {
        "action": "READ"
      }
    }
  }
}

Reply-Topic: analogInputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AI1": {
        "success": true,
        "value": <_FLOAT_>
      },
      "AI2": {
        "success": true,
        "value": <_FLOAT_>
      },
      "AI3": {
        "success": true,
        "value": <_FLOAT_>
      },
      "AI4": {
        "success": true,
        "value": <_FLOAT_>
      }
    }
  }
}
24.6.2 Usage Examples

24.7 Analog Outputs Actor

24.7.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.

a) Set analog outputs signal

Req-Topic: analogOutputs/config/in

Output: current within 0-20 mA

mode: on/off

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "mode": "on",
      "AO1": {
        "current": <_FLOAT_>
      },
      "AO2": {
        "current": <_FLOAT_>
      }
    }
  }
}

Reply-Topic: analogOutputs/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "mode": "on",
      "AO1": {
        "success": true,
        "current": <_FLOAT_>
      },
      "AO2": {
        "success": true,
        "current": <_FLOAT_>
      }
    }
  }
}
b) Set analog outputs

Req-Topic: analogOutputs/runtime/in

current: current within 0-20 mA

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AO1": {
        "action": "SET",
        "current": <_FLOAT_>
      },
      "AO2": {
        "action": "SET",
        "current": <_FLOAT_>
      }
    }
  }
}

Reply-Topic: analoigOutputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AO1": {
        "success": true,
        "current": <_FLOAT_>
      },
      "AO2": {
        "success": true,
        "current": <_FLOAT_>
      }
    }
  }
}
c) Read analog outputs settings

Req-Topic: analogOutputs/runtime/in

current: current within 0-20 mA

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "AO1": {
        "action": "READ"
      },
      "AO2": {
        "action": "READ"
      }
    }
  }
}

Reply-Topic: analogOutputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "AO1": {
        "success": true,
        "current": <_FLOAT_>
      },
      "AO2": {
        "success": true,
        "current": <_FLOAT_>
      }
    }
  }
}

24.8 Digital Inputs Actor

24.8.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credentials.

a) Set digital input pin/pins speed fast/slow

The fast speed setting supports edge detection speed up to 100 Hz and the slow speed settings supports up to 10 Hz.

Fast Mode generates a message on every I/O state change, which may result in a high message payload during operation. Fast Mode should therefore only be enabled when strictly required.

Req-Topic: digitalInputs/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "DI1": {
        "speed": "fast"
      },
      "DI2": {
        "speed": "slow"
      },
      "DI3": {
        "speed": "fast"
      },
      "DI4": {
        "speed": "fast"
      }
    }
  }
}

Reply-Topic: digitalInputs/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DI1": {
        "success": true,
        "speed": "fast"
      },
      "DI2": {
        "success": true,
        "speed": "slow"
      },
      "DI3": {
        "success": true,
        "speed": "fast"
      },
      "DI4": {
        "success": true,
        "speed": "fast"
      }
    }
  }
}
b) Get all digital input pins state

Req-Topic: digitalInputs/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: digitalInputs/runtime/out state: high/low

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DI1": {
        "success": true,
        "state": "high"
      },
      "DI2": {
        "success": true,
        "state": "low"
      },
      "DI3": {
        "success": true,
        "state": "high"
      },
      "DI4": {
        "success": true,
        "state": "low"
      }
    }
  }
}

24.9 Digital Outputs Actor

24.9.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this area requires no credencials.

a) Get all digital output pins state

Req-Topic: digitalOutputs/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: digitalOutputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DO1": {
        "success": true,
        "state": "low"
      },
      "DO2": {
        "success": true,
        "state": "high"
      },
      "DO3": {
        "success": true,
        "state": "high"
      },
      "DO4": {
        "success": true,
        "state": "low"
      },
      "DO5": {
        "success": true,
        "state": "low"
      },
      "DO6": {
        "success": true,
        "state": "low"
      },
      "DO7": {
        "success": true,
        "state": "low"
      },
      "DO8": {
        "success": true,
        "state": "low"
      }
    }
  }
}
b) Set all digital output pins state

Req-Topic: digitalOutputs/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskParams": {
      "DO1": {
        "action": "SET",
        "state": "low"
      },
      "DO2": {
        "action": "SET",
        "state": "high"
      },
      "DO3": {
        "action": "SET",
        "state": "high"
      },
      "DO4": {
        "action": "SET",
        "state": "low"
      },
      "DO5": {
        "action": "SET",
        "state": "low"
      },
      "DO6": {
        "action": "SET",
        "state": "low"
      },
      "DO7": {
        "action": "SET",
        "state": "low"
      },
      "DO8": {
        "action": "SET",
        "state": "low"
      }
    }
  }
}

Reply-Topic: digitalOutputs/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "D01": {
        "success": true,
        "state": "low"
      },
      "D02": {
        "success": true,
        "state": "high"
      },
      "D03": {
        "success": true,
        "state": "high"
      },
      "D04": {
        "success": true,
        "state": "high"
      },
      "D05": {
        "success": true,
        "state": "high"
      },
      "D06": {
        "success": true,
        "state": "low"
      },
      "D07": {
        "success": true,
        "state": "low"
      },
      "D08": {
        "success": true,
        "state": "low"
      }
    }
  }
}
24.9.2 Notes

If the busi2c-3 is not powered, we will get this:

Topic: digit a lOutputs/runtime/ out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "DO1": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO2": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO3": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO4": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO5": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO6": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO7": {
        "success": false,
        "state": "DO_not_powered"
      },
      "DO8": {
        "success": false,
        "state": "DO_not_powered"
      }
    }
  }
}

24.10 Joystick Actor

24.10.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtain peripherals data. Connecting to the broker for this Area requires no credencials.

a) Get all joystick pins state

Req-Topic: joystick/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "READ"
  }
}

Reply-Topic: joystick//runtime/out state: pressed/released

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "JLEFT": {
        "success": true,
        "state": "pressed"
      },
      "JRIGHT": {
        "success": true,
        "state": "released"
      },
      "JUP": {
        "success": true,
        "state": "released"
      },
      "JDOWN": {
        "success": true,
        "state": "released"
      },
      "JCENTER": {
        "success": true,
        "state": "released"
      }
    }
  }
}

24.11 Buzzer Actor

24.11.1 Overview

The Buzzer Actor is responsible for controlling the onboard buzzer through MQTT commands. It receives runtime commands on an MQTT input topic, validates the requested buzzer operation, drives the buzzerthrough GPIO using libgpiod, and publishes status/final responses on an MQTT output topic.

The actor currently controls GPIO line 25 on /dev/gpiochip0, with ACTIVE_LOW = False. It creates a

GpiodBuzzerDriver instance and routes incoming MQTT actions to runtime handlers.

The supported runtime actions are:

Action Description
BEEP Plays a finite beep sequence, an infinite beep sequence, or a continuous tone
STOP Stops the currently active buzzer playback
24.11.2 MQTT Topics
Topic Direction Description
buzzer/runtime/in Input Receives buzzer commands
buzzer/runtime/out Output Publishes status messages and final command responses

The actor subscribes to buzzer/runtime/in and publishes all status/final replies to buzzer/runtime/out.

24.11.3 Hardware and Datasheet Notes

The buzzer used is the MLT-8530 electro-magnetic SMD buzzer.

According to the datasheet:

Parameter Value
Rated voltage 3.6 Vo-p
Operating voltage 2.5 ~ 4.5 Vo-p
Rated current Max. 95 mA
Rated test frequency 2700 Hz
Duty cycle 50% square wave
Sound output Min. 80 dB at 10 cm
Coil resistance 16 ± 3 Ω
Resonant frequency 2700 Hz
24.11.4 BEEP

The BEEP action supports two modes:

Mode Description
sequence Plays one or more beeps with gaps between them
continuous Plays one continuous tone until STOP is received

If no mode is provided, the default mode is: sequence

All messages should be sent to the topic buzzer/runtime/in

a) Default Datasheet-Aligned Beep
{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
  "action": "BEEP"
  }
}
b) N Beeps

Play <BEEPS_QUANTITY> beeps at <FREQUENCY> Hz. Each beep lasts <BEEP_DURATION> seconds, with

<GAP_BETWEEN_BEEPS> seconds of silence between beeps.

{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
   "action": "BEEP",
   "params": {
      "frequency_hz": <FREQUENCY>,
      "duration_s": <BEEP_DURATION>,
      "count": <BEEPS_QUANTITY>,
      "gap_s": <GAP_BETWEEN_BEEPS> 
    }
  }
}

If you want to play repeated beeps forever until a STOP command arrives then you only need to pass the count: 0

c) Continuous Tone

Play one continuous <FREQUENCY> Hz tone until STOP.

{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
   "action": "BEEP",
   "params": {
      "mode": "continuous",
      "frequency_hz": <FREQUENCY>
    }
  }
}

If frequency_hz is omitted, the handler uses the configured default frequency.

d) Stop Buzzer

If you want to stop the beep sequence, just send this payload to the buzzer/runtime/in

{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
   "action": "STOP",
  }
}
e) Buzzer payload parameters table
Field Required Type Default Applies to Description
task Yes object - All requests Main task object. Contains the requested action and

optional parameters.

task.action Yes string - All requests Action to execute. Supported values: "BEEP" and

"STOP".

task.params No object {} BEEP Optional parameters for configuring the buzzer

behavior. Not needed for STOP.

task.params.mode No string "sequence" BEEP Playback mode. Supported values: "sequence" and

"continuous".

task.params.frequency_hz No number 2700.0 BEEP Buzzer frequency in Hz. Recommended/default value

is 2700 Hz , matching the buzzer resonant frequency.

task.params.duration_s No number 0.2 BEEP with

mode="sequence"

Duration of each beep, in seconds.
task.params.count No integer 1 BEEP with

mode="sequence"

Number of beeps to play. 0 means repeat forever

until STOP.

task.params.gap_s No number 0.15 BEEP with

mode="sequence"

Silence gap between beeps, in seconds.
task.params.mode ="continuous" No string - BEEP Plays one continuous tone until STOP . In this mode,

duration_s , count , and gap_s are ignored.

24.11.5 Buzzer - diagram
24.11.6 Buzzer Command timing charts - Examples

The following charts represent the command-level buzzer state over time.

They do not show the internal 2700 Hz switching frequency.

Instead, they show when the buzzer is logically:

State Meaning
1 Buzzer active / sound ON
0 Buzzer inactive / silence
a) Default BEEP command
{
"id": <TIMESTAMP>,
"origin": "APP",
"task": {
   "action": "BEEP",
  }
}

Default values used:

Parameter Value
duration_s 0.2 s
count 1
gap_s 0.15 s

Buzzer State

duration_s = 0.2 s

count = 1

b) BEEP Sequence - 5 beeps
{
"id": 1779789836000,
"origin": "APP",
"task": {
    "action": "BEEP",
    "params": {
      "duration_s": 1,
      "count": 5,
      "gap_s": <GAP_BETWEEN_BEEPS>
  } 
 }
}

Buzzer State



duration_s = 1.0s

gap_s = 0.5s

count = 5

c) Infinite BEEP Sequence

This happens when: "count": 0

{
"id": 1779789836000,
"origin": "APP",
"task": {
    "action": "BEEP",
    "params": {
       "duration_s": 1,
       "count": 0,
       "gap_s": 0.5
  }
 }
}

Buzzer State

duration_s = 1.0 gap_s = 0.5

count = 0

d) Continuous BEEP

In continuous mode, the buzzer remains ON until a STOP command is received.

{
"id": 1779789836000,
"origin": "APP",
"task": {
    "action": "BEEP",
    "params": {
       "mode": "continuous",
  }
 }
}

Buzzer State

mode = continuous

e) STOP

The STOP command immediately forces the buzzer to OFF.

Buzzer State

After STOP, the buzzer is forced to OFF.

24.12 INA232 actor

24.12.1 Overview

The INA Actor is responsible for reading the ATLAS INA232 power monitor and publishing the measuredelectrical values through MQTT.

The actor publishes:

Value Unit Description
voltage_v V Measured bus/input voltage
current_a A Measured current
power_w W Measured/calculated power

The INA232 is a current, voltage, and power monitor with an I²C/SMBus interface. It reports current, busvoltage, and power values through internal registers. The calibration register must be configured to obtainvalid current and power results.

24.12.2 Actor Behaviour

The INA Actor shall:

1. Start with a valid INA configuration.

2. Configure the INA232 device.

3. Read voltage, current and power once per second.

4. Publish the values to: ina/runtime/out

The actor does not need a request every second.

The publication is automatic and periodic.

24.12.3 Required Configuration

The actor requires a small configuration to correctly read and convert the INA232 measurements.

Field Type Required Description
enabled boolean Yes Enables or disables the INA actor
address string /integer Yes I²C address of the INA232 device
shunt_ohm number Yes Value of the shunt resistor in ohms
max_current_a number Yes Maximum expected current, used forcalibration
adcrange integer No INA232 shunt voltage range selection
publish_interval_ms integer Yes Runtime publish interval in milliseconds
rail_name string No Logical name of the monitored power rail
  • Default configuration
{
  "enabled": true,
  "address": "0x40",
  "shunt_ohm": 0.020,
  "publish_interval_ms": 1000,
  "rail_name": "atlas_input_power"
}
24.12.4 Configuration domain

Configuration messages are sent to:

ina/config/in

Configuration replies are published on:

ina/config/out

- GET_CONFIG

Returns the current INA Actor configuration

Request

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_CONFIG"
  }
}

Response

{
  "id": "<TIMESTAMP>",
  "origin": "INA",
  "task": {
    "action": "GET_CONFIG",
    "taskResult": {
      "success": true,
      "configured": true,
      "enabled": true,
      "address": "0x40",
      "shunt_ohm": 0.020,
      "publish_interval_ms": 1000
    }
  }
}
24.12.5 Runtime domain

Runtime messages are sent to:

ina/runtime/in

Runtime replies are published on:

ina/runtime/out

- Manual Runtime read

Request

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_POWER"
  }
}

Response

{
  "id": "<TIMESTAMP>",
  "origin": "INA",
  "task": {
    "action": "GET_POWER",
    "taskResult": {
      "success": true,
      "voltage_v": 24.12,
      "current_a": 0.481,
      "power_w": 11.6
    }
  }
}

- Automatic Runtime Publication

Publish topic:

ina/runtime/out

Period: 1000 ms === 1s

Response payload

{
  "id": "<TIMESTAMP>",
  "origin": "INA",
  "task": {
    "action": "PUBLISH_POWER",
    "taskResult": {
      "success": true,
      "voltage_v": 24.12,
      "current_a": 0.481,
      "power_w": 11.6
    }
  }
}
Field Type Required Description
success boolean - Indicates whether the read operation succeeded
voltage_v number V Measured bus/input voltage
current_a number A Measured current
power_w number W Measured power

24.13 Modem Actor

24.13.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker. Simplified interface to configure and obtainmodem (LTE) data. Connecting to the broker for this area requires no credentials.

24.13.2 Mobile (LTE Modem)

The Mobile actor manages the LTE modem using ModemManager (mmcli). It allows monitoring modem status, configuring connectivity (APN, operator,network mode), and performing diagnostics.

24.13.3 Scan Operators

Scans available network operators (requires SIM and modem enabled).

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SCAN_OPERATORS"
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "operators": [
        {
          "id": "26801",
          "name": "vodafone P",
          "status": "available"
        },
        {
          "id": "26806",
          "name": "MEO",
          "status": "available"
        }
      ]
    }
  }
}
24.13.4 Set Operator

The supported modes are:

  • auto → modem selects de operator automatically (default).
  • manual→ user forces a specific operator using operator_id.

- Operators are identified using MCC + MNC codes:

Operator Code Country
Vodafone PT 26801 Portugal
MEO 26806 Portugal
NOS 26803 Portugal

These values are obtained dynamically via SCAN_OPERATORS

  • Recommendations:

Default should always be auto

Use manual only when:

- You need to force roaming behavior

- You want to lock to a specific network for stability/testing

Auto Selection

Req-Topic: modem/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_OPERATOR",
    "taskParams": {
      "mode": "auto"
    }
  }
}

Reply-Topic: modem/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true
    }
  }
}
Manual Selection

Req-Topic: modem/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_OPERATOR",
    "taskParams": {
      "mode": "manual",
      "operator_id": "26801"
    }
  }
}

Reply-Topic: modem/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true
    }
  }
}
24.13.5 Set APN Configuration

Supports automatic (predefined APN) or custom configuration.

Actual Behavior

When SET_APN is executed, the system performs the following sequence:

  1. Disconnects the current data connection (if connected)
  2. Applies the new APN configuration
  3. Initiates a new connection using the provided APN
  4. Waits until the modem reaches connected state

This means a full reconnection is automatically performed.

No additional RESET or manual reconnection is required.

Impact & Considerations
  • Active data connection is interrupted
  • Ongoing communications (MQTT, HTTP, VPN, etc.) will be dropped
  • IP address may change after reconnection
  • Operation may take several seconds (typically 5–20s)
  • If connection fails, the modem may remain disconnected
Known APNs
Operator APN CONF

NAME

APN PROXY PORT MCC MNC AUTH

TYPE

APN

TYPE

CARRIER OBS.
MEO, UZO -- internet -- -- -- -- -- -- -- --
1nce -- iot.1nce.net -- -- -- -- -- -- -- --
Vodafone Vodafone

Internet

net2.vodafone.pt iproxy.vodafone.pt 80 268 01 PAP default unspecified Docs
Supported Modes
  • auto
  • custom
Mode Description
auto Uses modem default / SIM-provided APN
custom Uses user-defined APN credentials

- Auto APN (e.g. 1NCE)

Uses the default APN embedded in the modem or provided by the SIM.

Req-Topic: modem/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_APN",
    "taskParams": {
      "mode": "auto"
    }
  }
}

Reply-Topic: modem/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "apn": "internet",
      "success": true
    }
  }
}

- Custom APN

Allows full control over APN configuration.

Req-Topic: modem/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_APN",
    "taskParams": {
      "mode": "custom",
      "apn": "internet",
      "user": "user",
      "password": "pass"
    }
  }
}

Reply-Topic: modem/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "apn": "internet",
      "success": true
    }
  }
}
24.13.6 Get Modem Status

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_STATUS"
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "modem": {
        "present": true,
        "enabled": true,
        "state": "registered",
        "signal": 34,
        "access_tech": "lte",
        "operator": "vodafone P",
        "sim": "ready"
      }
    }
  }
}
24.13.7 Enable / Disable Modem

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_MODEM_STATE",
    "taskParams": {
      "enabled": true
    }
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "enabled": true,
      "success": true
    }
  }
}
24.13.8 Reset Modem

Performs a full modem reset and recovery sequence.

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "RESET"
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "success": true
    }
  }
}
Actual Behavior

When RESET is executed, the system performs a complete modem restart flow:

  1. Executes system-level reset: ltectl reset-modem
  2. The modem disappears from the system (USB re-enumeration)
  3. The system waits for the modem to reappear
  4. Re-discovers the modem path
  5. Waits until the modem becomes ready
  6. Waits until the modem is connected again

This is a full recovery sequence, including automatic reconnection.

Impact on active connection
  • Active data connection is immediately terminated
  • All ongoing communications (MQTT, VPN, HTTP, etc.) will be interrupted
  • Modem temporarily disappears from the system
  • A new network registration is performed
  • IP address will likely change
  • Total recovery time may take 10–120 seconds
When to use

Use RESET only when:

  • Modem is stuck in searching or not registering
  • Connected but no data traffic is possible
  • APN/operator changes are not taking effect
  • Modem becomes unresponsive or unstable
When NOT to Use

Avoid using RESET :

  • During OTA updates or file uploads
  • During critical real-time operations
  • If a simple reconnect ( SET_MODEM_STATE ) is sufficient
Application Considerations

Before RESET

  • Ensure no critical operations are ongoing
  • Persist any unsent or buffered data
  • Expect loss of connectivity

After RESET

  • Wait for modem to fully recover (can take up to ~2 minutes)
  • Re-check modem status using: GET_STATUS
  • Re-establish application-level connections: MQTT; VPN an Cloud sessions
24.13.9 Set Network Mode

Configures allowed radio technologies

Supported values:

  • 2g
  • 3g
  • 4g
  • auto

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SET_NETWORK_MODE",
    "taskParams": {
      "mode": "4g"
    }
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "mode": "4g",
      "success": true
    }
  }
}
24.13.10 Get Signal Strength

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_SIGNAL"
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "signal": 34,
      "unit": "%"
    }
  }
}
24.13.11 Get SIM card info

GET_SIM_INFO is a runtime action used to read SIM card information from the modem through ModemManager.

This action is read-only. It does not change the modem state, APN, operator, bearer, or NetworkManager configuration.

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "GET_SIM_INFO"
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "modem-actor",
  "task": {
    "taskResult": {
      "success": true,
      "sim": {
        "id": "0",
        "path": "/org/freedesktop/ModemManager1/SIM/0",
        "active": true,
        "iccid": "8935101234567890123",
        "imsi": "268060123456789",
        "operator_id": "26806",
        "operator_name": "MEO",
        "emergency_numbers": [
          "112"
        ],
        "preferred_networks": [
          "operator-code: 42507, access-technologies: gsm, umts, lte",
          "operator-code: 20810, access-technologies: gsm, umts, lte",
          "operator-code: 64710, access-technologies: gsm, umts, lte",
          "operator-code: 37001, access-technologies: gsm, umts, lte",
          "operator-code: 34002, access-technologies: gsm, umts, lte"
        ]
      }
    }
  }
}
Field Type Description
id number / string Same request ID received in the input payload.
origin string Actor name, usually modem-actor.
task.taskResult.success boolean Indicates if the SIM information was read successfully.
task.taskResult.sim.id string SIM object ID used by ModemManager. Usually 0.
task.taskResult.sim.path string ModemManager DBus path for the SIM object.
task.taskResult.sim.active boolean / null Indicates if the SIM is active, when available.
task.taskResult.sim.iccid string / null SIM ICCID / SIM identifier. This is the physical SIM card identifier.
task.taskResult.sim.imsi string / null IMSI associated with the SIM subscription.
task.taskResult.sim.operator_id string / null Mobile operator identifier from the SIM, when available.
task.taskResult.sim.operator_name string / null Operator name from the SIM, when available.
task.taskResult.sim.emergency_numbers array Emergency numbers reported by the SIM/modem.
task.taskResult.sim.preferred_networks array Preferred networks stored on the SIM, when available.
24.13.12 Test Modem

Performs a basic diagnostic test:

  • Modem detection
  • SIM presence
  • Network registration
  • Data connectivity

Req-Topic: modem/runtime/in

{
"id": "<TIMESTAMP>",
"origin": "APP",
"task": {
  "action": "TEST"
  }
}

Reply-Topic: modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "hw": true,
      "sim": true,
      "network": true,
      "data": true
    }
  }
}
24.13.13 Speed Test

Performs a low-data network speed test over the modem interface.

This command does not run a full bandwidth benchmark.

Instead, it performs a short and capped download burst on interface wwan0 , measures the number of received bytes during a fixed time window, and

returns an estimated download speed together with latency and a confidence level.

This approach is designed for IoT / field devices using capped cellular SIM cards, where a classic speed test would consume too much data.

Req-Topic: modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "action": "SPEED_TEST"
  }
}

Reply-Topic: modem/runtime/out Success reply:

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "download_mbps": 12.4,
      "success": true
    }
  }
}

Error reply Example when the modem is not connected:

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "download_mbps": 12.4,
      "success": true
    }
  }
}

Example when an unexpected internal error occurs:

{
  "id": "<TIMESTAMP>",
  "origin": "modem-actor",
  "task": {
    "taskResult": {
      "success": false,
      "reason": "unexpected_exception"
    }
  }
}
Reply parameters
Parameter Type Description
success boolean Indicates whether the speed test completed successfully. true = test executed, false = failed (see reason ).
download_mbps number Estimated download speed in megabits per second (Mbps). Calculated from the number of bytes received on interface

wwan0 during the measurement window.

bytes_sampled number Total number of received bytes measured on the modem interface ( wwan0 ) during the test window. Used as the raw input

for speed calculation.

duration_s number Measurement window duration in seconds. Current implementation uses 5 seconds.
latency_ms number null
confidence string Qualitative indicator of measurement reliability based on sampled bytes:• low → < 50,000 bytes• medium → 50,000–

299,999 bytes• high → ≥ 300,000 bytes

reason string Present only when success=false . Provides failure reason (e.g., not_connected (<state>) , unexpected_exception ).
Data consumption notice

This command performs a real network download and therefore consumes mobile data.

Although the test is designed to be low-data, it still generates traffic:

  • Typical consumption per test: ~100 KB to ~500 KB
  • Latency measurement adds a negligible amount (ICMP ping)

Estimated data usage

Frequency Estimated consumption
1 test/day (~100 KB) ~3 MB/month
1 test/day (~250 KB) ~7.5 MB/month
1 test/day (~500 KB) ~15 MB/month
Recommendation

For devices using capped SIM cards, it is recommended to:

  • Avoid running this test at high frequency
  • Use signal and modem status ( mmcli ) for regular monitoring
  • Reserve speed tests for:

- commissioning

- troubleshooting

- periodic health checks

Running frequent or extended tests may significantly impact the data allowance.

24.13.14 Get Raw Modem Info (Reserved)

Req-Topic: reserved/modem/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "modem-actor",
  "task": {
    "taskResult": {
      "success": false,
      "reason": "not_connected (registered)"
    }
  }
}

Reply-Topic: reserved/modem/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "DEV",
  "task": {
    "taskResult": {
      "raw": "mmcli -m 0 output..."
    }
  }
}
24.13.15 Example: Raw Modem Output ( mmcli )

Command:

mmcli -m 0 --output-json

Example output:

{
  "modem": {
    "3gpp": {
      "5gnr": {
        "registration-settings": {
          "drx-cycle": "--",
          "mico-mode": "--"
        }
      },
      "enabled-locks": [],
      "eps": {
        "initial-bearer": {
          "dbus-path": "--",
          "settings": {
            "apn": "--",
            "ip-type": "--",
            "password": "--",
            "user": "--"
          }
        },
        "ue-mode-operation": "--"
      },
      "imei": "862636056280785",
      "network-rejection-access-technology": "--",
      "network-rejection-error": "--",
      "network-rejection-operator-id": "--",
      "network-rejection-operator-name": "--",
      "operator-code": "--",
      "operator-name": "--",
      "packet-service-state": "--",
      "pco": "--",
      "registration-state": "--"
    },
    "cdma": {
      "activation-state": "--",
      "cdma1x-registration-state": "--",
      "esn": "--",
      "evdo-registration-state": "--",
      "meid": "--",
      "nid": "--",
      "sid": "--"
    },
    "dbus-path": "/org/freedesktop/ModemManager1/Modem/0",
    "generic": {
      "access-technologies": [],
      "bearers": [],
      "carrier-configuration": "ROW_Gen_VoLTE",
      "carrier-configuration-revision": "05010822",
      "current-bands": [
        "egsm",
        "dcs",
        "pcs",
        "g850",
        "utran-1",
        "utran-4",
        "utran-6",
        "utran-5",
        "utran-8",
        "utran-2",
        "eutran-1",
        "eutran-2",
        "eutran-3",
        "eutran-4",
        "eutran-5",
        "eutran-7",
        "eutran-8",
        "eutran-12",
        "eutran-13",
        "eutran-18",
        "eutran-19",
        "eutran-20",
        "eutran-25",
        "eutran-26",
        "eutran-28",
        "eutran-34",
        "eutran-38",
        "eutran-39",
        "eutran-40",
        "eutran-41",
        "eutran-66",
        "utran-19"
      ],
      "current-capabilities": [
        "gsm-umts, lte"
      ],
      "current-modes": "allowed: 4g; preferred: none",
      "device": "/sys/devices/platform/scb/fe9c0000.xhci/usb1/1-1/1-1.4",
      "device-identifier": "2c759b7021f62d2e26973150063ea040b3662a65",
      "drivers": [
        "option",
        "qmi_wwan"
      ],
      "equipment-identifier": "862636056280785",
      "hardware-revision": "10000",
      "manufacturer": "QUALCOMM INCORPORATED",
      "model": "SIMCOM_SIM7600G-H",
      "own-numbers": [],
      "physdev": "/sys/devices/platform/scb/fe9c0000.xhci/usb1/1-1/1-1.4",
      "plugin": "simtech",
      "ports": [
        "cdc-wdm0 (qmi)",
        "ttyUSB0 (ignored)",
        "ttyUSB1 (gps)",
        "ttyUSB2 (at)",
        "ttyUSB3 (at)",
        "ttyUSB4 (audio)",
        "wwan0 (net)"
      ],
      "power-state": "on",
      "primary-port": "cdc-wdm0",
      "primary-sim-slot": "1",
      "revision": "LE20B04SIM7600G22",
      "signal-quality": {
        "recent": "yes",
        "value": "0"
      },
      "sim": "/org/freedesktop/ModemManager1/SIM/0",
      "sim-slots": [
        "/org/freedesktop/ModemManager1/SIM/0",
        "/"
      ],
      "state": "failed",
      "state-failed-reason": "sim-missing",
      "supported-bands": [
        "egsm",
        "dcs",
        "pcs",
        "g850",
        "utran-1",
        "utran-4",
        "utran-6",
        "utran-5",
        "utran-8",
        "utran-2",
        "eutran-1",
        "eutran-2",
        "eutran-3",
        "eutran-4",
        "eutran-5",
        "eutran-7",
        "eutran-8",
        "eutran-12",
        "eutran-13",
        "eutran-18",
        "eutran-19",
        "eutran-20",
        "eutran-25",
        "eutran-26",
        "eutran-28",
        "eutran-34",
        "eutran-38",
        "eutran-39",
        "eutran-40",
        "eutran-41",
        "eutran-66",
        "utran-19"
      ],
      "supported-capabilities": [
        "gsm-umts, lte"
      ],
      "supported-ip-families": [
        "ipv4",
        "ipv6",
        "ipv4v6"
      ],
      "supported-modes": [
        "allowed: 2g; preferred: none",
        "allowed: 3g; preferred: none",
        "allowed: 4g; preferred: none",
        "allowed: 2g, 3g; preferred: 3g",
        "allowed: 2g, 3g; preferred: 2g",
        "allowed: 2g, 4g; preferred: 4g",
        "allowed: 2g, 4g; preferred: 2g",
        "allowed: 3g, 4g; preferred: 4g",
        "allowed: 3g, 4g; preferred: 3g",
        "allowed: 2g, 3g, 4g; preferred: 4g",
        "allowed: 2g, 3g, 4g; preferred: 3g",
        "allowed: 2g, 3g, 4g; preferred: 2g"
      ],
      "unlock-required": "--",
      "unlock-retries": []
    }
  }
}
Field Reference - mmcli -m 0 --output-json
JSON Path Meaning Example Value Notes / Interpretation
modem.dbus-path Internal modem path /org/.../Modem/0 Used by mmcli ( -m 0 )
modem.generic.manufacturer Modem vendor QUALCOMM INCORPORATED Hardware info
modem.generic.model Modem model SIM7600G-H
modem.generic.revision Firmware version LE20B04SIM7600G22 Useful for debugging
modem.generic.device Linux device path /sys/devices/... USB device
modem.generic.drivers Kernel drivers option, qmi_wwan Must be present
modem.generic.primary-port Control interface cdc-wdm0 Critical (QMI control)
modem.generic.ports Available interfaces ttyUSB*, wwan0 Data + AT + GPS
modem.generic.power-state Power status on
modem.generic.state Modem state failed Main status field
modem.generic.state-failed-reason Failure reason sim-missing Root cause of failure
modem.generic.signal-quality.value Signal strength (%) 0 0 = no signal
modem.generic.current-capabilities Active radio tech gsm-umts, lte
modem.generic.current-modes Active mode allowed: 4g Controlled via API
modem.generic.current-bands Active frequency bands [eutran-1, ...] Coverage related
modem.generic.supported-bands Supported bands [eutran-*, utran-*] Hardware capability
modem.generic.supported-ip-families IP support ipv4, ipv6, ipv4v6
modem.generic.sim SIM path /org/.../SIM/0
modem.generic.sim-slots SIM slots [slot1, slot2] Slot 2 empty here
modem.generic.primary-sim-slot Active SIM slot 1
modem.generic.bearers Active data sessions [ ] Empty = no connection
modem.3gpp.imei Device IMEI 862636056280785 Unique identifier
modem.3gpp.operator-name Network name -- Not available (no SIM)
modem.3gpp.operator-code MCC/MNC -- Not available
modem.3gpp.registration-state Network state -- Not registered
modem.3gpp.packet-service-state Data service state -- No data session
modem.3gpp.eps.initial-bearer.settings.apn APN -- Not set / no connection
24.13.16 Notes:
  • If no modem is detected: Reply-Topic: modem/runtime/out
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "modem": {
        "present": false
      }
    }
  }
}
  • If SIM is locked or missing: Reply-Topic: modem/runtime/out
{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "taskResult": {
      "modem": {
        "sim": "locked"
      }
    }
  }
}
  • Operator scan may take several seconds and should be handled asynchronously.
  • Some actions require:

- SIM card inserted

- Modem enabled

- cdc-wdm0 interface available

  • Signal strength is reported as percentage and may be cached by ModemActor.

24.14 CANopen Actor

24.14.1 App Interfacing

User App interface and functionalities exposed to the open part of the MQTT broker.

The CANopen Actor provides a generic protocol interface to CANopen devices.

The actor does NOT interpret device-specific meaning (Object Dictionary semantics).

It only handles communication (HOW to talk).

24.14.2 Configuration
Configure CANopen Nodes

Req-Topic: canopenRM8007/config/in

Stores CANopen defaults and logical node configuration inside the actor.

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "CONFIG_CANOPEN",
    "taskParams": {
      "defaults": {
        "sdo_timeout": "<SDO_TIMEOUT>"
      },
      "nodes": {
        "<NODE_NAME>": {
          "node_id": "<NODE_ID>",
          "steps_per_rev": "<STEPS_PER_REV>"
        }
      }
    }
  }
}

Reply-Topic: canopenRM8007/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "CONFIG_CANOPEN",
    "taskResult": {
      "defaults": {
        "success": true
      },
      "motor_1": {
        "success": true
      }
    }
  }
}

Request Parameters

Parameter Type Required Example Description
id string Yes "1777041089180" Unique request identifier. The same value isreturned in the response, allowing the applicationto match requests and responses.
origin string No "APP" Identifies who sent the request. Common values canbe

APP, NodeRED, CLI, or TestClient.

task object Yes {...} Main command object containing the CANopencommand alias and parameters.
task.alias string Yes "CONFIG_CANOPEN" Defines the command to execute. For this section,the alias must be

CONFIG_CANOPEN.

task.taskParams object Yes {...} Contains the configuration data to store inside theCANopen actor.
task.taskParams.defaults object No { "sdo_timeout":2.0 } Defines default CANopen settings used by the actorwhen no command-specific value is provided.
task.taskParams.defaults.sdo_timeout number No 2.0 Default timeout, in seconds, used for SDOoperations. For example, 2.0

means the actor waitsup to 2 seconds for an SDO response.

task.taskParams.nodes object Yes { "motor_1": {...}} List of logical CANopen nodes known by the actor.Each key is a user-defined node name.
task.taskParams.nodes.<NODE_NAME> object Yes "motor_1" Logical name used to reference a node later withoutrepeatedly sending its

node_id.

task.taskParams.nodes.<NODE_NAME>.node_id integer Yes 5 CANopen node ID on the CAN bus. Valid CANopennode IDs are normally in the range

1..127.

task.taskParams.nodes.<NODE_NAME>.steps_per_rev integer Recommended 4096 Number of raw position counts corresponding toone full mechanical revolution, 360°. The actor usesthis later to convert raw position into revolutions and angle_deg.

Response Parameters

Parameter Type Example Description
id string "1777041089180" Same request identifier received in the request. Used to correlate the

response with the original command.

origin string "canopen-actor" Identifies the component that generated the response. For successful

handler replies, this is canopen-actor.

task object {...} Main response object containing the executed alias and the command

result.

task.alias string "CONFIG_CANOPEN" Alias of the command that was executed.
task.taskResult object {...} Result object containing the configuration outcome.
task.taskResult.defaults.success boolean true Indicates that the defaults configuration was successfully stored. This

field is present only if defaults was included in the request.

task.taskResult.<NODE_NAME>.success boolean true Indicates that the logical node configuration was successfully stored.

Example: taskResult.motor_1.success = true.

task.taskResult.success boolean true Generic success field. This appears when no specific defaults or nodes

result is generated.

task.taskResult.error string "unknown alias

CONFIG_X"

Error description. This field is present only when the command fails.

CONFIG_CANOPEN does not communicate with the CANopen device directly. It stores logical node configuration inside the actor so that later runtime

commands can refer to nodes by name instead of always sending the numeric node_id.

Configure one CANopen Transmit PDO

Configures a TPDO to transmit position data.

The handler validates pdo_num as 1..4, defaults map_index to 0x6004, map_subindex to 0x00, map_bits to 32, transmission_type to 255 , event_timer_ms

to 20, and inhibit_time_100us to 0.

Req-Topic: canopenRM8007/config/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "CONFIG_POSITION_TPDO",
    "taskParams": {
      "node_id": 5,
      "pdo_num": 1,
      "map_index": "0x6004",
      "map_subindex": "0x00",
      "map_bits": 32,
      "transmission_type": 255,
      "event_timer_ms": 2,
      "inhibit_time_100us": 20,
      "offset": 0,
      "size": 4,
      "signed": false,
      "steps_per_rev": 4096,
      "timeout": 2.0
    }
  }
}

Reply-Topic: canopenRM8007/config/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "CONFIG_POSITION_TPDO",
    "taskResult": {
      "success": true,
      "node_id": 5,
      "pdo_num": 1,
      "comm_index": 6144,
      "map_index": 6656,
      "mapped_object": "0x6004:00/32",
      "transmission_type": 255,
      "event_timer_ms": 2,
      "inhibit_time_100us": 20,
      "cob_id": 389
    }
  }
}
Parameter description
Parameter Type Required Default Description
node_id int Yes* CANopen node ID.
node string Yes* Logical node name configured previously with CONFIG_CANOPEN.
pdo_num int No 1 TPDO number. Valid range: 1..4.
map_index int/string No 0x6004 Object dictionary index to map. Hex strings such as "0x6004" are

supported.

map_subindex int/string No 0x00 Object dictionary subindex.
map_bits int No 32 Number of mapped bits.
transmission_type int No 255 CANopen TPDO transmission type.
event_timer_ms int No 20 TPDO event timer in milliseconds.
inhibit_time_100us int No 0 Inhibit time in 100 μs units.
offset int No 0 Byte offset used later when decoding PDO position.
size int No 4 Number of bytes used later when decoding PDO position.
signed bool No false Whether decoded raw position should be interpreted as signed.
steps_per_rev int Recommended 4096 if saved into node

config

Encoder steps per revolution.
timeout float No actor default SDO/NMT operation timeout.
24.14.3 Runtime Operations

Supported runtime aliases include READ, READ_CONTINUOUS, STOP_READ_CONTINUOUS, READ_PDO_CONTINUOUS, STOP_READ_PDO_CONTINUOUS, PING, NMT_COMMAND, SDO_READ, SDO_WRITE, READ_HEARTBEAT, RECV_PDO, RECV_EMCY, and QUERY_NODE_INFO.

NMT Control

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "CONFIG_CANOPEN",
    "taskParams": {
      "defaults": {
        "sdo_timeout": "<SDO_TIMEOUT>"
      },
      "nodes": {
        "<NODE_NAME>": {
          "node_id": "<NODE_ID>",
          "steps_per_rev": "<STEPS_PER_REV>"
        }
      }
    }
  }
}

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "NMT_COMMAND",
    "taskResult": {
      "success": true,
      "id": "nmt-start-node5",
      "node_id": 5,
      "command": "START",
      "confirmed": true,
      "state": null
    }
  }
}
  • Supported NMT Commands
Command Meaning Notes
START Puts the node into Operational state. If wait = true, the actor waits for heartbeat state OPERATIONAL.
STOP Puts the node into Stopped state. If wait = true, the actor waits for heartbeat state STOPPED.
PRE_OP Puts the node into Pre-Operational state. Used before operations such as PDO remapping.
PRE-OP Same as PRE_OP. Alternative accepted spelling.
PREOP Same as PRE_OP. Alternative accepted spelling.
PRE_OPERATIONAL Same as PRE_OP. Alternative accepted spelling.
RESET_NODE Resets the CANopen node application. If wait = true, the actor waits for boot-up heartbeat.
RESET Same as RESET_NODE. Alternative accepted spelling.
RESET_COMM Resets CANopen communication. Sends NMT reset communication command.
  • Request Parameters
Parameter Type Required Example Description
id string Yes "<TIMESTAMP>" Unique request identifier. The same value is returned in the response.
origin string No "APP" Identifies the sender of the request, for example APP , NodeRED , CLI , or

TestClient.

task object Yes {...} Main command object containing the command alias and parameters.
task.alias string Yes "NMT_COMMAND" Defines the command to execute. For this operation, it must be

NMT_COMMAND.

task.taskParams object Yes {...} Contains the NMT command parameters.
task.taskParams.node_id integer Yes 5 Numeric CANopen node ID that will receive the NMT command.
task.taskParams.nodeId integer Yes 5 Alternative spelling for node_id.
task.taskParams.node string Yes "motor_1" Logical node name previously configured with CONFIG_CANOPEN.
task.taskParams.command string No "START" NMT command to send. If omitted, the actor defaults to START.
task.taskParams.wait boolean No false If true, the actor waits for heartbeat/state confirmation when supported. If

false, the command is sent without waiting for confirmation.

task.taskParams.timeout number No 5.0 Timeout, in seconds, used when waiting for NMT confirmation.

Default is 5.0.

task.taskParams.sdo_timeout number No 2.0 Internal timeout used when creating/updating the CANopen node wrapper.

Usually not required for basic NMT usage.

  • Response Parameters
Parameter Type Example Description
id string "<TIMESTAMP>" Same request identifier received in the request. Used to correlate request and

response.

origin string "canopen-actor" Identifies the component that generated the response.
task object {...} Main response object.
task.alias string "NMT_COMMAND" Alias of the command that was executed.
task.taskResult object {...} Result object containing the NMT command result.
task.taskResult.success boolean true Indicates whether the actor successfully executed the NMT command.
task.taskResult.id string "nmt-start-node5" Internal/request ID returned by the CANopen RPC call. Usually matches the

original request id.

task.taskResult.node_id integer 5 CANopen node ID that received the NMT command.
task.taskResult.command string "START" NMT command that was executed. For aliases such as RESET , the response may

normalize the command to RESET_NODE.

task.taskResult.confirmed boolean true Indicates whether the command was considered successful. If wait = false , this

usually means the command was sent successfully. If wait = true , this means

the expected heartbeat/state confirmation was received.

task.taskResult.state string/null null Confirmed NMT state when wait = true and state confirmation is available.

Otherwise it is null . Possible values include OPERATIONAL , STOPPED , and PRE_OP.

task.taskResult.error string "unsupported NMT

command X"

Error description. Present only when the command fails.
SDO Read

Reads an object dictionary value using SDO upload.

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "SDO_READ",
    "taskParams": {
      "node_id": 5,
      "index": "0x6004",
      "subindex": "0x00",
      "timeout": 2.0
    }
  }
}

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "SDO_READ",
    "taskResult": {
      "success": true,
      "id": "sdo-read-position-node5",
      "node_id": 5,
      "index": 24580,
      "subindex": 0,
      "value": 123456
    }
  }
}
  • Request Parameters
Parameter Type Required Example Description
id string Yes "<TIMESTAMP>" Unique request identifier. The same value is returned in the response.
origin string No "APP" Identifies the sender of the request, for example APP , NodeRED , CLI , or

TestClient.

task object Yes {...} Main command object containing the command alias and parameters.
task.alias string Yes "SDO_READ" Defines the command to execute. For this operation, it must be SDO_READ.
task.taskParams object Yes {...} Contains the SDO read parameters.
task.taskParams.node_id integer Yes 5 Numeric CANopen node ID to read from.
task.taskParams.nodeId integer Yes 5 Alternative spelling for node_id.
task.taskParams.node string Yes "motor_1" Logical node name previously configured with CONFIG_CANOPEN.
task.taskParams.index integer/string Yes "0x6004" CANopen object dictionary index to read. Hex strings such as "0x6004"

are supported.

task.taskParams.subindex integer/string No "0x00" CANopen object dictionary subindex to read. If omitted, defaults to 0.
task.taskParams.timeout number No 2.0 Timeout, in seconds, used for the SDO read operation. If omitted, the

actor default SDO timeout is used.

  • Response Parameters
Parameter Type Example Description
id string "<TIMESTAMP>" Same request identifier received in the request. Used to correlate request and

response.

origin string "canopen-actor" Identifies the component that generated the response.
task object {...} Main response object.
task.alias string "SDO_READ" Alias of the command that was executed.
task.taskResult object {...} Result object containing the SDO read result.

task

task.taskResult.success boolean true Indicates whether the SDO read was successful.
task.taskResult.id string "sdo-read-positionnode5" Internal/request ID returned by the CANopen RPC call. Usually matches the

original request id.

task.taskResult.node_id integer 5 CANopen node ID that was read.
task.taskResult.index integer 24580 Object dictionary index that was read, returned as decimal. Example: 24580 =

0x6004.

task.taskResult.subindex integer 0 Object dictionary subindex that was read.
task.taskResult.value integer 123456 Raw value returned by the SDO read operation.

task.

task.taskResult.error string "SDO timeout

0x6004:00"

Error description. Present only when the command fails.

SDO

  • SDO Write

Writes an object dictionary value using SDO download.

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "SDO_WRITE",
    "taskParams": {
      "node_id": 5,
      "index": "0x6003",
      "subindex": "0x00",
      "value": 0,
      "size": 4,
      "timeout": 2.0
    }
  }
}

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "SDO_WRITE",
    "taskResult": {
      "success": true,
      "id": "sdo-write-node5",
      "node_id": 5,
      "index": 24579,
      "subindex": 0,
      "value": 0,
      "size": 4
    }
  }
}
  • Parameter descirption
Parameter Type Required Default Description
node_id / nodeId / node int/string Yes CANopen node reference.
index int/string Yes Object dictionary index.
subindex int/string No 0 Object dictionary subindex.
value int/string Yes Value to write.
size int No 4 Number of bytes: usually 1 , 2 , or 4.
timeout float No actor default SDO timeout in seconds.
  • Request Parameters
Parameter Type Required Example Description
id string Yes "<TIMESTAMP>" Unique request identifier. The same value is returned in the response.
origin string No "APP" Identifies the sender of the request, for example APP , NodeRED , CLI , or

TestClient.

task object Yes {...} Main command object containing the command alias and parameters.
task.alias string Yes "SDO_WRITE" Defines the command to execute. For this operation, it must be

SDO_WRITE.

task.taskParams object Yes {...} Contains the SDO write parameters.
task.taskParams.node_id integer Yes* 5 Numeric CANopen node ID to write to.
task.taskParams.nodeId integer Yes* 5 Alternative spelling for node_id.
task.taskParams.node string Yes* "motor_1" Logical node name previously configured with CONFIG_CANOPEN.
task.taskParams.index integer/string Yes "0x6003" CANopen object dictionary index to write. Hex strings such as "0x6003"

are supported.

task.taskParams.subindex integer/string No "0x00" CANopen object dictionary subindex to write. If omitted, defaults to 0.
task.taskParams.value integer/string Yes 0 Value to write into the selected object dictionary entry. Hex strings are

also supported.

task.taskParams.size integer No 4 Number of bytes to write. Valid values are normally 1 , 2 , 3 , or 4 . If

omitted, defaults to 4.

task.taskParams.timeout number No 2.0 Timeout, in seconds, used for the SDO write operation. If omitted, the

actor default SDO timeout is used.

  • Response Parameters
Parameter Type Example Description
id string "<TIMESTAMP>" Same request identifier received in the request. Used to correlate request andresponse.
origin string "canopen-actor" Identifies the component that generated the response.
task object {...} Main response object.
task.alias string "SDO_WRITE" Alias of the command that was executed.
task.taskResult object {...} Result object containing the SDO write result.
task.taskResult.success boolean true Indicates whether the SDO write was successful.
task.taskResult.id string "sdo-write-node5" Internal/request ID returned by the CANopen RPC call.

Usually matches theoriginal request id.

task.taskResult.node_id integer 5 CANopen node ID that was written to.
task.taskResult.index integer 24579 Object dictionary index that was written, returned as decimal.

Example: 24579 =0x6003.

task.taskResult.subindex integer 0 Object dictionary subindex that was written.
task.taskResult.value integer 0 Value that was written.
task.taskResult.size integer 4 Number of bytes written.
task.taskResult.error string "SDO abort 0x6003:00 ->..." Error description. Present only when the command fails.
Read Node State

Reads position and returns raw value, revolutions, and angle. Internally, this reads the configured position object, defaulting to

0x6004:00. If steps_per_rev is not provided, the owner reads 0x6501:00 to obtain it.

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "READ",
    "taskParams": {
      "node_id": 5,
      "index": "0x6004",
      "subindex": "0x00",
      "steps_per_rev": 4096,
      "timeout": 2.0
    }
  }
}

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ",
    "taskResult": {
      "success": true,
      "id": "read-node5",
      "node_id": 5,
      "raw": 1024,
      "steps_per_rev": 4096,
      "revolutions": 0.25,
      "angle_deg": 90.0,
      "index": 24580,
      "subindex": 0
    }
  }
}
  • Request Parameters
Parameter Type Required Example Description
id string Yes "<TIMESTAMP>" Unique request identifier. The same value is returned in theresponse.
origin string No "APP" Identifies the sender of the request, for example APP, NodeRED, CLI, or TestClient.
task object Yes {...} Main command object containing the command alias andparameters.
task.alias string Yes "READ" Defines the command to execute. For this operation, it must be READ.
task.taskParams object Yes {...} Contains the position read parameters.
task.taskParams.node_id integer Yes* 5 Numeric CANopen node ID to read from.
task.taskParams.nodeId integer Yes* 5 Alternative spelling for node_id.
task.taskParams.node string Yes* "motor_1" Logical node name previously configured with CONFIG_CANOPEN.
task.taskParams.index integer/string No "0x6004" CANopen object dictionary index used as the raw positionsource. If omitted, defaults to 0x6004.
task.taskParams.subindex integer/string No "0x00" CANopen object dictionary subindex used as the raw positionsource. If omitted, defaults to 0x00.
task.taskParams.steps_per_rev integer Recommended 4096 Number of raw counts per mechanical revolution. Used tocalculate

revolutions and angle_deg. If omitted, the ownerattempts to read 0x6501:00.

task.taskParams.timeout number No 2.0 Timeout, in seconds, used for the internal SDO reads. Ifomitted, the actor default SDO timeout is used.
task.taskParams.sdo_timeout number No 2.0 Internal SDO timeout used when creating/updating the nodewrapper. Usually not required.
  • Response Parameters
Parameter Type Example Description
id string "<TIMESTAMP>" Same request identifier received in the request. Used to correlate request andresponse.
origin string "canopen-actor" Identifies the component that generated the response.
task object {...} Main response object.
task.alias string "READ" Alias of the command that was executed.
task.taskResult object {...} Result object containing the position read result.
task.taskResult.success boolean true Indicates whether the position read was successful.
task.taskResult.id string "read-node5" Internal/request ID returned by the CANopen RPC call. Usually matches theoriginal request id.
task.taskResult.node_id integer 5 CANopen node ID that was read.
task.taskResult.raw integer 1024 Raw position value read from the selected object dictionary entry.
task.taskResult.steps_per_rev integer 4096 Number of raw counts per revolution used for the conversion.
task.taskResult.revolutions number 0.25 Raw position converted into revolutions. Example: 1024 / 4096 = 0.25.
task.taskResult.angle_deg number 90.0 Position inside one revolution, in degrees. Example: 0.25 × 360 = 90°.
task.taskResult.index integer 24580 Object dictionary index read as the raw position source. Example: 24580 =0x6004.
task.taskResult.subindex integer 0 Object dictionary subindex read as the raw position source.
task.taskResult.error string "SDO timeout0x6004:00" Error description. Present only when the command fails.
READ SDO Continuous

Starts continuous SDO-based position reading.

The initial command returns an acknowledgement. After that, continuous samples are published repeatedly to canopen/runtime/out

The continuous loop requires a single node reference and requires steps_per_rev.

  • Start request

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskParams": {
      "node_id": 5,
      "steps_per_rev": 4096,
      "index": "0x6004",
      "subindex": "0x00",
      "timeout": 0.2,
      "interval_ms": 20
    }
  }
}

Reply-Topic: canopenRM8007/runtime/out

// Start acknowledgement
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": true,
      "mode": "single",
      "interval_ms": 20
    }
  }
}
// Continuous sample response
{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskResult": {
      "success": true,
      "node_id": 5,
      "angle_deg": 90.0,
      "steps_per_rev": 4096,
      "revolutions": 0.25,
      "raw": 1024,
      "index": 24580,
      "subindex": 0,
      "continuous": true,
      "request_id": "read-cont-node5"
    }
  }
}
  • Start Request Parameters
Parameter Type Required Example Description
id string Yes "<TIMESTAMP>" Unique request identifier. Continuous sample responses include

this value as request_id.

origin string No "APP" Identifies the sender of the request, for example APP, NodeRED,

CLI, or TestClient.

task object Yes {...} Main command object containing the command alias and

parameters.

task.alias string Yes "READ_CONTINUOUS" Defines the command to execute. For this operation, it must be

READ_CONTINUOUS.

task.taskParams object Yes {...} Contains the continuous read parameters.
task.taskParams.node_id integer Yes* 5 Numeric CANopen node ID to read continuously.
task.taskParams.nodeId integer Yes* 5 Alternative spelling for node_id.
task.taskParams.node string Yes* "motor_1" Logical node name previously configured with CONFIG_CANOPEN.
task.taskParams.steps_per_rev integer Yes** 4096 Number of raw counts per mechanical revolution. Required by

the fast continuous read loop to calculate revolutions and

angle_deg.

task.taskParams.index integer/string No "0x6004" CANopen object dictionary index used as the raw position

source. If omitted, defaults to 0x6004.

task.taskParams.subindex integer/string No "0x00" CANopen object dictionary subindex used as the raw position

source. If omitted, defaults to 0x00.

task.taskParams.timeout number No 0.2 Timeout, in seconds, used for each fast SDO read cycle. If

omitted, defaults to 0.2.

task.taskParams.interval_ms integer No 20 Delay between continuous read cycles, in milliseconds. If 0 , the

loop runs again immediately after each cycle yields control.

task.taskParams.action string No "START" Optional action. If set to STOP , OFF , CANCEL , or DISABLE , the

actor stops the continuous read loop instead of starting it.

  • Start Acknowledgement Response Parameters
Parameter Type Example Description
id string "<TIMESTAMP>" Same request identifier received in the start request.
origin string "canopen-actor" Identifies the component that generated the response.
task object {...} Main response object.
task.alias string "READ_CONTINUOUS" Alias of the command that was executed.
task.taskResult object {...} Result object confirming that continuous reading was started.
task.taskResult.success boolean true Indicates whether the start command was accepted.
task.taskResult.running boolean true Indicates that the continuous read loop is running.
task.taskResult.mode string "single" Read mode. In this fast continuous path, a single node is used when node_id ,

nodeId , or node is provided.

task.taskResult.interval_ms integer 20 Configured delay between continuous read cycles, in milliseconds.
task.taskResult.error string "no configured nodes" Error description. Present only when the start command fails.
  • Continuous Sample Response Parameters
Parameter Type Example Description
id integer/string 1777041089180 Sample response ID generated by the actor for each read cycle.
origin string "canopen-actor" Identifies the component that generated the sample response.
task object {...} Main response object.
task.alias string "READ_CONTINUOUS" Alias of the running continuous command.
task.taskResult object {...} Result object containing one continuous position sample.
task.taskResult.success boolean true Indicates whether this specific read cycle was successful.
task.taskResult.node_id integer 5 CANopen node ID that was read.
task.taskResult.angle_deg number 90.0 Position inside one revolution, in degrees.
task.taskResult.steps_per_rev integer 4096 Number of raw counts per revolution used for conversion.
task.taskResult.revolutions number 0.25 Raw position converted into revolutions.
task.taskResult.raw integer 1024 Raw position value read from the node.
task.taskResult.index integer 24580 Object dictionary index read as the raw position source. Example: 24580 =

0x6004.

task.taskResult.subindex integer 0 Object dictionary subindex read as the raw position source.
task.taskResult.continuous boolean true Marks this response as a continuous sample, not just the initial

acknowledgement.

task.taskResult.request_id string "read-cont-node5" Original request id that started the continuous loop. Useful to correlate

samples with the start command.

task.taskResult.error string "operation failed" Error description for a failed sample. Present only when a read cycle fails.
Stop request

You can stop using either STOP_READ_CONTINUOUS :

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "STOP_READ_CONTINUOUS",
    "taskParams": {}
  }
}

Or by sending READ_CONTINUOUS with action: "STOP" :

{
  "id": "stop-read-cont",
  "origin": "APP",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskParams": {
      "action": "STOP"
    }
  }
}

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "stop-read-cont",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": false,
      "stopped": true
    }
  }
}
  • Stop Request Parameters
Parameter Type Required Example Description
id string Yes "stop-read-cont" Unique request identifier.
origin string No "APP" Identifies the sender of the request.
task.alias string Yes "READ_CONTINUOUS" or

"STOP_READ_CONTINUOUS"

Command used to stop the continuous read loop.
task.taskParams.action string No "STOP" When using READ_CONTINUOUS , set action to STOP , OFF , CANCEL ,

or DISABLE to stop the loop. Not required when using

STOP_READ_CONTINUOUS.

  • Stop Response Parameters
Parameter Type Example Description
id string "stop-read-cont" Same request identifier received in the stop request.
origin string "canopen-actor" Identifies the component that generated the response.
task.alias string "READ_CONTINUOUS" Alias returned by the stop handler.
task.taskResult.success boolean true Indicates whether the stop request was processed successfully.
task.taskResult.running boolean false Indicates that the continuous read loop is no longer running.
task.taskResult.stopped boolean true Indicates whether there was an active task that was actually stopped. If no continuous

task was running, this may be false.

Continuous PDO Reading

Starts continuous PDO-based position reading.

This command does not perform repeated SDO reads. Instead, it waits for TPDO frames already being transmitted by the CANopen node.

Normally, the TPDO should be configured first using CONFIG_POSITION_TPDO.

The initial command returns an acknowledgement. After that, continuous sample responses are published repeatedly to: canopenRM8007/runtime/out

  • Start Request

Req-Topic: canopenRM8007/runtime/in

{
  "id": "<TIMESTAMP>",
  "origin": "APP",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskParams": {
      "node_id": 5,
      "pdo_num": 1,
      "steps_per_rev": 4096,
      "offset": 0,
      "size": 4,
      "signed": false,
      "timeout": 1.0,
      "interval_ms": 20
    }
  }
}
  • Start Acknowledgement

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": true,
      "mode": "pdo",
      "pdo_num": 1,
      "interval_ms": 20
    }
  }
}
  • Continuous Sample Response

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "<TIMESTAMP>",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskResult": {
      "success": true,
      "node_id": 5,
      "pdo_num": 1,
      "angle_deg": 90.0,
      "steps_per_rev": 4096,
      "revolutions": 0.25,
      "raw": 1024,
      "data": [0, 4, 0, 0],
      "offset": 0,
      "size": 4,
      "signed": false,
      "continuous": true,
      "request_id": "read-pdo-cont-node5"
    }
  }
}

Start Request Parameters

Parameter Type Required Example Description
id string Yes "<TIMESTAMP>" Unique request identifier. Continuous sample responses include

this value as request_id.

origin string No "APP" Identifies the sender of the request, for example APP , NodeRED ,

CLI , or TestClient.

task object Yes {...} Main command object containing the command alias and

parameters.

task.alias string Yes "READ_PDO_CONTINUOUS" Defines the command to execute.
task.taskParams object Yes {...} Contains the PDO continuous read parameters.
task.taskParams.node_id integer Yes* 5 Numeric CANopen node ID to read from.
task.taskParams.nodeId integer Yes* 5 Alternative spelling for node_id.
task.taskParams.node string Yes* "motor_1" Logical node name previously configured with CONFIG_CANOPEN. If

used, the actor can reuse saved steps_per_rev , pdo_num ,

offset , size , and signed values from the node configuration.

task.taskParams.pdo_num integer No 1 TPDO number to listen to. If omitted, defaults to 1.
task.taskParams.steps_per_rev integer Yes** 4096 Number of raw position counts per mechanical revolution. Used

to convert raw into revolutions and angle_deg.

task.taskParams.offset integer No 0 Byte offset inside the PDO payload where the position value

starts.

task.taskParams.size integer No 4 Number of bytes to decode from the PDO payload. For a 32-bit

position value, use 4.

task.taskParams.signed boolean No false Defines whether the raw value should be decoded as signed or

unsigned.

task.taskParams.timeout number No 1.0 Timeout, in seconds, while waiting for each TPDO frame. If no

TPDO is received within this time, the cycle fails.

task.taskParams.interval_ms integer No 20 Delay between read cycles, in milliseconds. If 0 , the loop

immediately starts the next cycle after yielding control.

task.taskParams.action string No "START" Optional action. If set to STOP , OFF , CANCEL , or DISABLE , the

actor stops the continuous loop instead of starting it.

  • Start Acknowledgement Response Parameters
Parameter Type Example Description
id string "<TIMESTAMP>" Same request identifier received in the start request.
origin string "canopen-actor" Identifies the component that generated the response.
task object {...} Main response object.
task.alias string "READ_PDO_CONTINUOUS" Alias of the command that was executed.
task.taskResult object {...} Result object confirming whether the continuous PDO read

was started.

task.taskResult.success boolean true Indicates whether the start command was accepted.
task.taskResult.running boolean true Indicates that the continuous PDO read loop is running.
task.taskResult.mode string "pdo" Indicates that the loop is using PDO reception mode.
task.taskResult.pdo_num integer 1 TPDO number being listened to.
task.taskResult.interval_ms integer 20 Configured delay between read cycles, in milliseconds.
task.taskResult.error string "READ_PDO_CONTINUOUS requires a single

node"

Error description. Present only when the start command

fails.

  • Continuous Sample Response Parameters
Parameter Type Example Description
id integer/string 1777041089180 Sample response ID generated by the actor for each PDO read cycle.
origin string "canopen-actor" Identifies the component that generated the sample.
task object {...} Main response object.
task.alias string "READ_PDO_CONTINUOUS" Alias of the running continuous command.

task.

task.taskResult object {...} Result object containing one decoded PDO position sample.
task.taskResult.success boolean true Indicates whether this specific PDO read cycle was successful.
task.taskResult.node_id integer 5 CANopen node ID that produced the TPDO.
task.taskResult.pdo_num integer 1 TPDO number received and decoded.
task.taskResult.angle_deg number 90.0 Position inside one revolution, in degrees.
task.taskResult.steps_per_rev integer 4096 Number of raw counts per revolution used for conversion.
task.taskResult.revolutions number 0.25 Raw position converted into revolutions. Example: 1024 / 4096 = 0.25 .
task.taskResult.raw integer 1024 Decoded raw position value from the PDO payload.
task.taskResult.data array [0, 4, 0, 0] Raw PDO payload bytes received from the CANopen node.
task.taskResult.offset integer 0 Byte offset used to extract the raw position value from data.
task.taskResult.size integer 4 Number of bytes decoded from data.
task.taskResult.signed boolean false Indicates whether the raw value was decoded as signed or unsigned.
task.taskResult.continuous boolean true Marks this response as a continuous sample.
task.taskResult.request_id string "read-pdo-cont-node5" Original request id that started the continuous loop. Useful to

correlate samples with the start command.

task.taskResult.error string "pdo operation failed" Error description. Present only when a sample fails.
Stop Request

Req-Topic: canopenRM8007/runtime/in

{
  "id": "stop-pdo-cont",
  "origin": "APP",
  "task": {
    "alias": "STOP_READ_PDO_CONTINUOUS",
    "taskParams": {}
  }
}

Alternative stop request using READ_PDO_CONTINUOUS:

{
  "id": "stop-pdo-cont",
  "origin": "APP",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskParams": {
      "action": "STOP"
    }
  }
}
Stop Response

Reply-Topic: canopenRM8007/runtime/out

{
  "id": "stop-pdo-cont",
  "origin": "canopen-actor",
  "task": {
    "alias": "READ_PDO_CONTINUOUS",
    "taskResult": {
      "success": true,
      "running": false,
      "stopped": true
    }
  }
}
  • Stop Response Parameters
Parameter Type Example Description
id string "stop-pdo-cont" Same request identifier received in the stop request.
origin string "canopen-actor" Identifies the component that generated the response.
task.alias string "READ_PDO_CONTINUOUS" Alias returned by the stop handler.
task.taskResult.success boolean true Indicates whether the stop request was processed successfully.
task.taskResult.running boolean false Indicates that the continuous PDO loop is no longer running.
task.taskResult.stopped boolean true Indicates whether there was an active continuous task that was actually stopped. If

no task was running, this may be false.

Decode Logic

The received PDO payload is decoded using:

  • offset: first byte to read from the PDO payload;
  • size: number of bytes to read;
  • signed: whether the value is signed or unsigned;
  • steps_per_rev: scaling factor used to calculate revolutions and angle.

The raw value is decoded as little-endian:

raw = int.from_bytes(data[offset : offset + size], byteorder="little", signed=signed)

Then:

revolutions = raw / steps_per_rev

angle_deg = ((raw % steps_per_rev) / steps_per_rev) * 360.0

24.14.4 Design Principles
  • Protocol-Only Actor

The CANopen Actor is responsible for:

- CAN frame encoding/decoding;

- SDO communication;

- PDO reception (raw);

- NMT control;

- Heartbeat monitoring.

  • No Device Semantics

The actor:

Does NOT know:

- What 0x6004 represents;

- Units (RPM, mm, °C, etc.);

- Device-specific logic.

Only returns:

- Raw values;

- Protocol-level responses.

  • Node Management

- Nodes must be defined via configuration;

- Actor maintains node state internally;

- Supports multiple nodes simultaneously.

Summary

The CANopen Actor:

- Implements CANopen protocol communication;

- Provides generic MQTT interface;

- Supports multi-node networks;

- Keeps strict separation between transport and semantics.


25. Included Software Stack

26. Hardware Libraries

[IMAGE PLACEHOLDER]

PA Name Requirements
PA000000074 SENSBLUE MONARCH Gateway
Name Firmware v. Requirements
PA000000065 SENSBLUE RS-485 Dissolved Oxygen Probe AT-SB-PROBE-DO-P-C1, w/ 15m cable w/connector
PA000000085 SENSBLUE RS-485 Dissolved Oxygen Probe AT-SB-PROBE-DO-T-C1, w/ 15m cable w/connector 10.70
PA000000091 SENSBLUE RS-485 Dissolved CO2 Sensor Probe AT-SB-PROBE-CO2-P-5000-C1, w/ 15m cable w/connector
PA000000086 SENSBLUE RS-485 Low Conductivity Probe AT-SB-PROBE-LC-P-C1, w/ 15m cable w/connector 10.70
PA000000087 SENSBLUE RS-485 Medium Conductivity Probe AT-SB-PROBE-MC-P-C1, w/ 15m cable w/connector 10.70
PA000000068 SENSBLUE RS-485 High Conductivity Probe AT-SB-PROBE-HC-P-C1, w/ 15m cable w/connector 10.70
PA000000089 SENSBLUE RS-485 Salinity/Conductivity/TDS Probe AT-SB-PROBE-S-P-C1, w/ 15m cable w/connector
PA000000067 SENSBLUE RS-485 pH Probe AT-SB-PROBE-pH-P, w/ 15m cable w/conector 10.70
PA000000088 SENSBLUE RS-485 ORP Probe AT-SB-PROBE-ORP-P-C1, w/ 15m cable w/connector
PA000000069 SENSBLUE RS-485 Nitrates (NO3) Probe AT-SB-PROBE-NO3-P, w/ 15m cable w/connector 10.70
PA000000090 SENSBLUE RS-485 Ammonia Nitrogen (NH4-N) Sensor Probe AT-SB-PROBE-NH4-P-C1, w/ 15m cable w/connector
PA000000066 SENSBLUE RS-485 Turbidity Probe AT-SB-PROBE-T-P, w/ 15m cable w/connector 10.70
PA000000073 SENSBLUE RS-485 Multiparameter Probe AT-SB-PROBE-MP-P-C1, w/ 15m cable w/connector 10.71

28. Accessories

PA Name Requirements

29. Document History

Version Description Date
SBADATAv0.1 First version of SENSBLUE ATLAS Datasheet 11/03/2026

30. SENSBLUE ATLAS in-the-field

[IMAGE PLACEHOLDER]