uBridge Server
uBridge server¶
uBridge runs as a daemon (systemd service), which constantly monitors the machine's USB ports for new enumerated devices.
If the detected device is a uThing™, the server notifies the connected plugins, optionally configures the new device, and listens for incoming data from the uThing™'s.
Each new sensor message is then streamed to the subscribed plugins.
The messaging model is built on top of the socket library NNG (Nanomessage New Generation). NNG is an evolution of Nanomessage and ZeroMQ.
Quick start (systemd)¶
sudo make install # from the uBridge build directory
sudo systemctl enable ubridge ubridge-server
sudo systemctl start ubridge
Check status and logs:
systemctl status ubridge-server.service
tail -f /tmp/ubridge.log
Transports¶
The uBridge can be configured to use two different transports:
- IPC: Uses Linux Message Queues for efficient communication when the uBridge and plugin applications run on the same machine.
- TCP: Uses TCP sockets, in case that the client (plugin) applications run on different machines.
All messages between Server and Clients are encapsulated into JSON objects.
The uBridge server communicates with the clients (plugins) via two sockets:
Control socket (REQ/REP)¶
The Config socket uses the Request / Response model. The clients send Requests to uBridge (i.e. setConfig, getConfig, getDevices, queryDevice, sendCommand, getStatistics) and get the corresponding responses with status or information.
Examples using nngcat:
# List devices
nngcat --req --dial ipc:///tmp/ubridgeReqResp --data '{"request":"getDevices"}'
# Get statistics
nngcat --req --dial ipc:///tmp/ubridgeReqResp --data '{"request":"getStatistics"}'
# Query a specific device by channel ID
nngcat --req --dial ipc:///tmp/ubridgeReqResp --data '{"request":"queryDevice","channelID":"uThing::VOC_1234","query":{"status":true}}'
# Send a command to a device
nngcat --req --dial ipc:///tmp/ubridgeReqResp --data '{"request":"sendCommand","channelID":"uThing::VOC_1234","command":{"led":true}}'
Here is an example of a response message to a getDevices request:
{
"channelID": "uThing::MNL_D657",
"fwVersion": "1.0.3",
"name": "uThing::MNL rev.A",
"serialNumber": "28AE9B9745B5D657"
},
{
"channelID": "uThing::VOC_F8B6",
"fwVersion": "1.3.2",
"name": "uThing::VOC rev.2",
"serialNumber": "7F8D2D3FEF89F8B6"
}
getStatistics request:
{
"bridgeUpTime": 1764846,
"devices": {
"uThing::MNL_D657": {
"msgReceived": 1771,
"msgSent": 4,
"upTime": 262823477
},
"uThing::VOC_F8B6": {
"msgReceived": 592,
"msgSent": 4,
"upTime": 443589765
}
},
"numConnectedDevices": 2,
"receivedMsgPerSec": 1.34,
"sentMsgPerSec": 0.01
}
Stream socket (PUB)¶
The Stream socket is used for the uBridge to stream sensor data to the plugins. The plugins can subscribe to specific "topics" (for example a single sensor), or to all the incoming sensor data:
uBridgeClient.subscribe("/sensors", subsMessageHandler); //subscribe to all sensors
uBridgeClient.subscribe("/sensors/uThing::VOC_9142", subsMessageHandler); //specific unit
The assigned names ("channelID") can be obtained from the config socket with a getDevices request.
The sensors are identified by their type and the 4 last characters of their serial number in order to differentiate multiple sensors of the same type connected.
Source code & Installation¶
Using with the InfluxDB plugin in a RaspberryPi
At the moment of writing, InfluxDB 2.0 hasn't been released for the armhf port yet, so check the InfluxDB plugin documentation for instructions of installing the arm64 Raspbian version before starting. NOTE: This is only required if InfluxDB will be installed locally.
The source code and installation instructions are located here: https://github.com/ohmtech-io/uBridge
Configuration¶
All the configuration files are installed under /etc/ubridge
Here is the default configuration file for the uBridge component:
Note that the format is JSON-like, with added comments enclosed in "/* */" blocks
{
"devNameBase":"",/* If this field is left empty, the bridge will try to find devices
in '/dev/ttyACM*' and '/dev/ttyUSB*' - For MacOS, use '/dev/cu'*/
"configSockUrl":"ipc:///tmp/ubridgeReqResp",/* The sockets for the Request Response Server and data Streamer*/
"streamSockUrl":"ipc:///tmp/ubridgeStream",/* If the client app runs in the same machine, IPC is
more efficient. If a different host is used (as with a client running in a Docker instance)
use TCP host:port ("tcp://localhost:8001")*/
"maxDevices":10/* Maximum number of devices supported */
}
-
"devNameBase": each Linux distribution assigns different base names for the Virtual Serial Ports.
For example, Debian assigns
/dev/ACM0to the first VCP device enumerated. By default (leave this field empty), uBridge will look into/dev/ttyACM*and/dev/ttyUSB*devices. -
"configSockUrl": Socket name for the configuration Request/Respond messages.
Using
ipc:///tmp/*, NNG will use Linux Message Queues when the client/s are running on the same machine, this is more efficient than TCP sockets.For TCP transport, use
tcp://server:port(i.e.tcp://localhost:8001). This can be handy if the plugins are running inside a Docker container, or in a remote server. -
"streamSockUrl": Socket name for the message streaming (Publish / Subscribe model).
-
"maxDevices": This will limit the maximum number of devices supported if needed (extra enumerated uThing's will be ignored).
NOTE: Remember to restart the server after changing the configuration file (sudo systemctl restart ubridge-server.service).
Service files¶
The installation provides two service units:
ubridge.service: uBridge main service.ubridge-server.service: convenience wrapper to ensure the bridge is started and monitored.
You can override unit configuration via drop-in files under /etc/systemd/system/ if needed.
Monitoring¶
Check running status of the service¶
systemctl status ubridge-server.service
Log file¶
The log files for the uBridge and plugins are located in the /tmp directory:
tail /tmp/ubridge.log
Troubleshooting¶
- Missing NNG or LibSerial: ensure
libserial-devandnngare installed and visible to the linker (often/usr/local/lib); runsudo ldconfigafter installing NNG. - Permission errors on serial ports: add your user to the appropriate group (e.g.
dialout) or run the service as root. - No devices found: verify device nodes under
/dev/ttyACM*//dev/ttyUSB*(or setdevNameBase). On macOS, setdevNameBaseto/dev/cufor development. - No PUB messages: confirm
streamSockUrlmatches between server and client and that the subscriber topic prefix is correct.
IPC permissions (PermissionDenied)¶
If a client gets PermissionDenied when connecting to ipc:///tmp/ubridgeReqResp or ipc:///tmp/ubridgeStream, it’s due to filesystem permissions on the created IPC endpoints.
- Quick check:
ls -l /tmp/ubridge*
- Options:
- For development, switch to TCP in
ubridgeConfig.jsonand in clients - Run the client with elevated permissions:
sudo ... - Run the service as your user so the sockets are owned by you (edit service and set
User=<youruser>; restart) - Relax the file creation mask in the service: add
UMask=0002(or000) to the unit and restart - Use a dedicated runtime dir and group permissions:
- In the service:
RuntimeDirectory=ubridge,RuntimeDirectoryMode=0775,User=ubridge,Group=ubridge,UMask=0002 - Update config to
ipc:///run/ubridge/ubridgeReqRespandipc:///run/ubridge/ubridgeStream
- In the service:
- For development, switch to TCP in