{
    "version": "https://jsonfeed.org/version/1",
    "title": "RemotiveLabs Developer Blog",
    "home_page_url": "https://developer.remotivelabs.com/blog",
    "description": "RemotiveDocs - Guides, code samples & more Blog",
    "items": [
        {
            "id": "https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings",
            "content_html": "<p>A good recording of a drive is often the most useful test data you will ever have. With\nRemotiveTopology you can play that recording back onto virtual buses and watch it in\nRemotiveStudio, with the camera videos in sync. This post covers how to set that up and\nwhat we use it for day to day.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"why-play-back-a-recording\">Why play back a recording<a href=\"https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings#why-play-back-a-recording\" class=\"hash-link\" aria-label=\"Direct link to Why play back a recording\" title=\"Direct link to Why play back a recording\">​</a></h2>\n<p>Playback, also called open loop simulation, sends recorded vehicle data back onto the\nchannels of a running topology as if the vehicle were there. Three things make that useful:</p>\n<ul>\n<li><strong>Debugging.</strong> When something odd happens on a test drive, you can replay those 20\nseconds as often as you like, pause on the frame where it goes wrong and look at it\nnext to the front camera video.</li>\n<li><strong>Developing against real data.</strong> A behavioral model or an app that consumes signals\ngets realistic input from a laptop, without a car or a test rig. You can also mix\nrecorded data with a running topology (closed loop simulation), for example by feeding\nrecorded GPS positions to an Android Automotive instance while the climate controls still\nrespond.</li>\n<li><strong>Regression testing.</strong> The same recording gives the same input every time, so a test case\nthat runs against it in CI shows you when behavior changes.</li>\n</ul>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"describe-the-drive-as-a-recording-session\">Describe the drive as a recording session<a href=\"https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings#describe-the-drive-as-a-recording-session\" class=\"hash-link\" aria-label=\"Direct link to Describe the drive as a recording session\" title=\"Direct link to Describe the drive as a recording session\">​</a></h2>\n<p>Everything starts with a recording session: a YAML file with the session's start and end\ntime, the recording files, any video files, and a mapping from the recording equipment's\ndevice names to the platform's channels. RemotiveTopology reads CAN dumps and CSV in long\nformat (timestamp, signal name, signal value). This example is taken from the docs:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">recording</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">session</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.2</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> Roundabout left turn</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">start_time</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> 1753865338s</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">end_time</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> 1753865361s</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">files</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">location</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ./candata.log</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> recording</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">location</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> front.mp4</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> front</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> video</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">start_time</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> 1753865335s</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">mapping</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">includes</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ../equipment.mapping.yaml</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Some things to watch for:</p>\n<ul>\n<li>The mapping is what turns <code>can0</code> on the logger into <code>DriverCan</code> in your platform. If\nthe device names already match the channel names, you don't need one. If you keep the\nmapping in its own file, several recordings made with the same equipment can share it.</li>\n<li>Videos need a <code>name</code> (<code>front</code>, <code>rear</code> and so on). Dashboards pick videos by that name, so\none dashboard works for every session from the same car. Set the video's <code>start_time</code>\ntoo: the camera rarely starts at the same moment as the logger. Use MP4 with H.264 and\nAAC, since RemotiveStudio runs in a browser.</li>\n<li>You can have several sessions that point at the same recording files, for example to\ncut out the interesting part of a long drive.</li>\n</ul>\n<p>You don't have to write the file by hand: <code>remotive topology recording-session create -f candump.log</code> generates a session from one or more recording files, and <code>recording-session recalculate</code> updates its start and end time after you change file offsets. See\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/recordings/concepts\">Recording concepts</a>\nfor the details.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"start-a-topology-to-play-it-on\">Start a topology to play it on<a href=\"https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings#start-a-topology-to-play-it-on\" class=\"hash-link\" aria-label=\"Direct link to Start a topology to play it on\" title=\"Direct link to Start a topology to play it on\">​</a></h2>\n<p>Playback needs a running topology instance whose platform has every channel the mapping\nuses. The instance can have more channels than that, so a recording of only one bus works\ntoo. To get a simple instance with default settings and no behavioral models, generate it\nfrom the session, then build and run it:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology recording-session instantiate roundabout.recordingsession.yaml playback.instance.yaml</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology generate </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> playback.instance.yaml build</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:#d73a49\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> build/</span><span class=\"token operator\" style=\"color:#393A34\">&lt;</span><span class=\"token plain\">instance</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\">/docker-compose.yml </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--profile</span><span class=\"token plain\"> ui up</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>You don't need a new instance for every recording. If you recorded several drives with the\nsame platform, you can use one instance to play all of them. The\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/recordings/usage\">Usage</a> page\nalso shows how to add your own signals that aren't on the vehicle platform, such as emulated\nGPS, through a CSV file and an extra channel.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"watch-it-in-remotivestudio\">Watch it in RemotiveStudio<a href=\"https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings#watch-it-in-remotivestudio\" class=\"hash-link\" aria-label=\"Direct link to Watch it in RemotiveStudio\" title=\"Direct link to Watch it in RemotiveStudio\">​</a></h2>\n<p>Start RemotiveStudio in your workspace with <code>remotive studio .</code> and open a dashboard. The\n<strong>Add Panel</strong> picker has two groups. Use <strong>Open recording</strong> from the recordings group\nto load the session for playback, then add a <strong>Video</strong> panel for each camera. The\nvideo stays in sync with the signal timeline. Next to them, add the chart panels you need: a\n<strong>Time series</strong> for the signals you care about, a <strong>Trace</strong> for raw frames, a <strong>Map</strong> if the\nrecording has latitude and longitude, or a <strong>Frame distribution</strong> to see which frames\nare sent most often.</p>\n<p>One tip from experience: use only one dashboard tab. RemotiveStudio warns if it sees more\nthan one dashboard running, and you may find that playback controls stop responding or\nvideos don't play. The <a href=\"https://developer.remotivelabs.com/docs/remotive-studio/dashboard/add-panel\">Add a panel</a>\npage lists every panel type.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"control-playback-from-the-command-line\">Control playback from the command line<a href=\"https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings#control-playback-from-the-command-line\" class=\"hash-link\" aria-label=\"Direct link to Control playback from the command line\" title=\"Direct link to Control playback from the command line\">​</a></h2>\n<p>The same controls are in RemotiveCLI, which is handy from a script or when you only want\nto jump to the interesting moment. Offsets can be given in minutes, seconds, milliseconds\nor microseconds:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token builtin class-name\">export</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:#36acaa\">REMOTIVE_RECORDING_SESSION_PATH</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token operator\" style=\"color:#393A34\">&lt;</span><span class=\"token plain\">recording session</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker playback </span><span class=\"token function\" style=\"color:#d73a49\">open</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token string variable\" style=\"color:#36acaa\">$REMOTIVE_RECORDING_SESSION_PATH</span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker playback play </span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token string variable\" style=\"color:#36acaa\">$REMOTIVE_RECORDING_SESSION_PATH</span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--offset</span><span class=\"token plain\"> 10s</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker playback pause </span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token string variable\" style=\"color:#36acaa\">$REMOTIVE_RECORDING_SESSION_PATH</span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker playback seek </span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token string variable\" style=\"color:#36acaa\">$REMOTIVE_RECORDING_SESSION_PATH</span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--offset</span><span class=\"token plain\"> 15000ms</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker playback repeat </span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token string variable\" style=\"color:#36acaa\">$REMOTIVE_RECORDING_SESSION_PATH</span><span class=\"token string\" style=\"color:#e3116c\">\"</span><span class=\"token plain\"> --start-offset 10s --end-offset 20s</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker playback status </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--stream</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>repeat</code> loops a part of the recording, which is useful while you change a behavioral\nmodel and want the same few seconds over and over. Run it with <code>--clear</code> to stop the loop.\nEvery command takes <code>--url</code> if your broker isn't on <code>http://localhost:50051</code>. All\noptions are in the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-cli/cli_man_pages\">RemotiveCLI manual</a>.</p>\n<p>For regression tests, playback can also be controlled from code, for example from a test\ncase running in its own container in the topology, and the topology can be shut down when the tests\nare done (see <a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/running\">Running</a>).\nTo try all of this without a recording of your own, the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/recordings/examples\">examples</a>\ninclude a Tesla Model 3 drive with two CAN buses and four camera videos.</p>",
            "url": "https://developer.remotivelabs.com/blog/2026/09/15/playing-back-recordings",
            "title": "Playing back recordings",
            "summary": "Replaying a recorded drive in RemotiveStudio and RemotiveCLI, and why that helps with debugging, development and regression tests.",
            "date_modified": "2026-09-15T00:00:00.000Z",
            "author": {
                "name": "Ola Nilsson"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/09/03/sniffing",
            "content_html": "<p>Plug into a CAN bus and you get a wall of hex: IDs, lengths and data bytes scrolling past faster\nthan you can read them. This post walks through how I capture that traffic on Linux, keep it in\na file, and turn it into named signals with a DBC using RemotiveTopology and RemotiveStudio.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"what-sniffing-gives-you\">What sniffing gives you<a href=\"https://developer.remotivelabs.com/blog/2026/09/03/sniffing#what-sniffing-gives-you\" class=\"hash-link\" aria-label=\"Direct link to What sniffing gives you\" title=\"Direct link to What sniffing gives you\">​</a></h2>\n<p>Sniffing means listening to a bus without taking part in it. You see every frame that ECUs send,\nwith timestamps, which is exactly what you want when you're asking questions like \"does the BCM\nactually send the turn signal frame when I flip the stalk?\" or \"how often does this frame show up?\"</p>\n<p>What you don't get from the wire is meaning. A CAN frame is an ID and up to 8 bytes (64 for CAN\nFD). Which bits are vehicle speed, and how to scale them, lives in a signal database such as a\nDBC. So sniffing is really two jobs: capture the raw frames, then decode them.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"setup-get-the-bus-onto-a-socketcan-interface\">Setup: get the bus onto a SocketCAN interface<a href=\"https://developer.remotivelabs.com/blog/2026/09/03/sniffing#setup-get-the-bus-onto-a-socketcan-interface\" class=\"hash-link\" aria-label=\"Direct link to Setup: get the bus onto a SocketCAN interface\" title=\"Direct link to Setup: get the bus onto a SocketCAN interface\">​</a></h2>\n<p>Everything below assumes Linux, because it relies on SocketCAN. Once your CAN adapter shows up as\na network interface, standard tooling such as <code>candump</code> from can-utils works against it. The\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/instance\">RemotiveTopology docs</a>\nrecommend giving the interface a name that matches your architecture rather than <code>can0</code>:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token function\" style=\"color:#d73a49\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">ip</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">link</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\">set</span><span class=\"token plain\"> can0 name drivercan0</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>That small habit pays off later, when you have three adapters plugged in and need to remember\nwhich one is on the driver CAN.</p>\n<p>If the traffic you want to look at comes from containers, for example behavioral models in a\ntopology, <a href=\"https://developer.remotivelabs.com/docs/remotive-bus/configuration\">RemotiveBus</a> can expose\nit on the host. A <code>vcan</code> network with a <code>host_device</code> creates a virtual CAN interface on the host,\nso you can sniff simulated traffic with the same tools you use on a real vehicle:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> vcan</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">device</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> mybus</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">host_device</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> myhostbus   </span><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># Name of the virtual CAN interface to create on the host</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>To go the other way and let containers use a physical bus, use <code>type: can</code> with <code>host_device</code>\npointing at the adapter. Note that Docker appends a <code>0</code> to the device name inside the container.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"capturing-traffic\">Capturing traffic<a href=\"https://developer.remotivelabs.com/blog/2026/09/03/sniffing#capturing-traffic\" class=\"hash-link\" aria-label=\"Direct link to Capturing traffic\" title=\"Direct link to Capturing traffic\">​</a></h2>\n<p>With the interface up, start with a live look:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">candump drivercan0</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Once you've confirmed frames are flowing, log them to a file instead. <code>candump -l</code> writes a\n<code>candump-&lt;date&gt;.log</code> file in the current directory, in the \"CAN dump\" format that both\nRemotiveTopology and RemotiveCloud read. Drive the scenario you care about, then stop it with\nCtrl+C.</p>\n<p>Before you do anything else with the log, check it with RemotiveCLI. If a colleague needs the\ncapture in another format, the same tool converts between <code>.log</code>, <code>.asc</code> and <code>.blf</code>:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive tools can validate candump-2026-09-03_101500.log --print-to-terminal</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive tools can convert candump-2026-09-03_101500.log drive.blf</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Both commands are described in the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-cli/cli_man_pages\">RemotiveCLI reference</a>.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"making-sense-of-what-you-captured\">Making sense of what you captured<a href=\"https://developer.remotivelabs.com/blog/2026/09/03/sniffing#making-sense-of-what-you-captured\" class=\"hash-link\" aria-label=\"Direct link to Making sense of what you captured\" title=\"Direct link to Making sense of what you captured\">​</a></h2>\n<p>Now for the decoding. In RemotiveTopology, the signal database belongs to a channel in your\nplatform. A DBC doesn't say which bus it describes, so you name the channel yourself\n(<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/platform\">platform docs</a>):</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">platform</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.15</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">channels</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">DriverCan</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> can</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">database</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ../databases/driver_can.dbc</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Next, wrap the log in a recording session, and add a\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/recordings/concepts\">recording mapping</a>\nthat connects the interface name in the log to the platform channel:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology recording-session create </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> candump-2026-09-03_101500.log drive.recordingsession.yaml</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">recording</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">mapping</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">devices</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">drivercan0</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> DriverCan</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>If you named the interface the same as the channel, you can skip the mapping: a default mapping\nfrom same-name devices is created automatically. Then create an instance for playback, generate\nit and start it with the UI profile, as described in\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/recordings/usage\">recordings usage</a>:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology recording-session instantiate drive.recordingsession.yaml drive.instance.yaml</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology generate </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> drive.instance.yaml build</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:#d73a49\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> build/</span><span class=\"token operator\" style=\"color:#393A34\">&lt;</span><span class=\"token plain\">instance</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\">/docker-compose.yml </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--profile</span><span class=\"token plain\"> ui up</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>In RemotiveStudio, the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/topology/signal-view\">Signal view</a> lists every\nframe and signal in the DBC, with unit, factor/offset and named values, which is handy for\nfinding the signal you're after. Then build a dashboard with a few\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/dashboard/add-panel\">panels</a>, with an <strong>Open\nrecording</strong> panel to play back the log:</p>\n<ul>\n<li><strong>Frame distribution</strong> shows which frames are on the bus and how often. A frame that's missing,\nor one far more frequent than expected, is often the first clue.</li>\n<li><strong>Trace</strong> is the decoded version of <code>candump</code>: timestamp, frame ID, frame name and raw bytes,\nwith signal values when you expand a row.</li>\n<li><strong>Time series</strong> plots the signals themselves, so you can see that brake pedal position goes up\njust before vehicle speed goes down.</li>\n</ul>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"other-ways-to-look-at-the-same-data\">Other ways to look at the same data<a href=\"https://developer.remotivelabs.com/blog/2026/09/03/sniffing#other-ways-to-look-at-the-same-data\" class=\"hash-link\" aria-label=\"Direct link to Other ways to look at the same data\" title=\"Direct link to Other ways to look at the same data\">​</a></h2>\n<p>If you'd rather not set up a platform, you can upload the log to\n<a href=\"https://developer.remotivelabs.com/docs/cloud/Project/Recordings\">RemotiveCloud</a>, either by drag and\ndrop or with <code>remotive cloud recordings upload</code>. It matches the recording against the signal\ndatabases in your project and suggests the best fit. And for Ethernet traffic between containers,\nincluding SOME/IP, <a href=\"https://developer.remotivelabs.com/docs/remotive-topology/tools/wireshark\">Edgeshark and Wireshark</a>\nlet you inspect each connection in a running topology.</p>\n<p>Whichever route you take, the idea is the same: capture first, keep the raw log, and let the\nsignal database do the decoding. The log stays useful long after the drive is over.</p>",
            "url": "https://developer.remotivelabs.com/blog/2026/09/03/sniffing",
            "title": "Sniffing CAN traffic and making sense of it",
            "summary": "Capture raw CAN traffic with candump, then decode it with a DBC in RemotiveTopology and RemotiveStudio.",
            "date_modified": "2026-09-03T00:00:00.000Z",
            "author": {
                "name": "Ola Nilsson"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci",
            "content_html": "<p>A topology that only runs on your laptop is a good start, but the real payoff comes when\nevery pull request spins it up, runs the tests and throws it away again. This post walks\nthrough doing that in GitHub Actions: generate the topology, start it with a test container,\nlet pytest talk to the RemotiveBroker, and fail the build when a test fails.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"a-tester-container-in-the-instance\">A tester container in the instance<a href=\"https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci#a-tester-container-in-the-instance\" class=\"hash-link\" aria-label=\"Direct link to A tester container in the instance\" title=\"Direct link to A tester container in the instance\">​</a></h2>\n<p>RemotiveTopology lets you add your own containers to an instance, next to the ECUs. The\nnice part for CI is that a test runner can be one of them: it starts inside the topology,\non the same networks as everything else, and reaches the TopologyBroker by name. Put it\nbehind a <a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/instance\">profile</a> so it\nonly runs when you ask for it:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">containers</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">tester</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">profiles</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">tester</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">build</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:#00a4db\">dockerfile</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ../../../python</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">runner.dockerfile</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">volumes</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ../tests</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\">/app</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">working_dir</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> /app</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">command</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"pytest --broker_url=http://topology-broker.com:50051 -s -vv\"</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>The Dockerfile only needs Python and your test dependencies: pytest, pytest-asyncio and the\n<code>remotivelabs-topology</code> package. Profiles map straight to docker compose profiles, so the\ntester stays out of the way when you start the topology without <code>--profile tester</code> to poke\nat it by hand.</p>\n<p>One thing to check before moving to a hosted runner: CAN channels default to RemotiveBus,\nwhich needs to be installed on the host. If you don't need SocketCAN in CI, switch the\ninstance to UDP emulation, which works anywhere without extra setup:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">settings</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">can</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">default_driver</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> udp</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"writing-the-tests\">Writing the tests<a href=\"https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci#writing-the-tests\" class=\"hash-link\" aria-label=\"Direct link to Writing the tests\" title=\"Direct link to Writing the tests\">​</a></h2>\n<p>Tests use the <a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/apis\">RemotiveTopology framework</a>,\nthe Python library you also write behavioral models with. A small <code>conftest.py</code> turns the\n<code>--broker_url</code> option from the container command into a <code>BrokerClient</code> fixture. The default\npoints at <code>localhost:50051</code>, which is where the broker is forwarded when you run the topology\ninteractively, so the same tests run from your editor too:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># tests/conftest.py</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> pytest_asyncio</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">broker </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> BrokerClient</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">pytest_addoption</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">parser</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    parser</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">addoption</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"--broker_url\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> default</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token string\" style=\"color:#e3116c\">\"http://localhost:50051\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token decorator annotation punctuation\" style=\"color:#393A34\">@pytest_asyncio</span><span class=\"token decorator annotation punctuation\" style=\"color:#393A34\">.</span><span class=\"token decorator annotation punctuation\" style=\"color:#393A34\">fixture</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">with</span><span class=\"token plain\"> BrokerClient</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">url</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">config</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">getoption</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"--broker_url\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">as</span><span class=\"token plain\"> client</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">yield</span><span class=\"token plain\"> client</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>A test then subscribes to frames in a namespace (named <code>&lt;ECU&gt;-&lt;Channel&gt;</code>) and waits for the\nsignal values it expects. This one is adapted from the\n<a href=\"https://developer.remotivelabs.com/apis/python/remotivelabs/topology\" target=\"_blank\" rel=\"noopener noreferrer\">testing examples in the API docs</a>:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># tests/test_hazard_lights.py</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">broker </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> BrokerClient</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">testing</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">frames </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> capture_frames</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">test_hazard_light_sequence</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> BrokerClient</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:#393A34\">-</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:#36acaa\">None</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">with</span><span class=\"token plain\"> capture_frames</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"HazardLightControlUnit-DriverCan0\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        frames</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token string\" style=\"color:#e3116c\">\"HazardLightButton\"</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">as</span><span class=\"token plain\"> cap</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> cap</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">wait_for_signal_values</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token string\" style=\"color:#e3116c\">\"HazardLightButton\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token string\" style=\"color:#e3116c\">\"HazardLightButton.HazardLightButton\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            values</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token number\" style=\"color:#36acaa\">0</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:#36acaa\">1</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:#36acaa\">0</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            timeout</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token number\" style=\"color:#36acaa\">5.0</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>The tests are async, so set <code>asyncio_mode = auto</code> in your pytest configuration (or mark\nthem with <code>@pytest.mark.asyncio</code>). If you're unsure which namespaces exist, start the\ntopology and run <code>remotive broker signals namespaces --url http://localhost:50051</code>.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"credentials-for-the-runner\">Credentials for the runner<a href=\"https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci#credentials-for-the-runner\" class=\"hash-link\" aria-label=\"Direct link to Credentials for the runner\" title=\"Direct link to Credentials for the runner\">​</a></h2>\n<p>Running a topology checks your organization's RemotiveTopology subscription, and a CI job\nshouldn't do that with someone's personal login. Create a\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/ci\">service account</a> with the\nRemotiveTopology Executor role instead:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive cloud service-accounts create ci-runner </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--role</span><span class=\"token plain\"> org/topologyRunner </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--project</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:#393A34\">&lt;</span><span class=\"token plain\">project id</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive cloud service-accounts tokens create --service-account ci-runner </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--project</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:#393A34\">&lt;</span><span class=\"token plain\">project id</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive cloud auth print-access-token </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--account</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:#393A34\">&lt;</span><span class=\"token plain\">email </span><span class=\"token keyword\" style=\"color:#00009f\">for</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">service</span><span class=\"token plain\"> account</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive cloud organizations list</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Store the token as a repository secret, <code>REMOTIVE_CLOUD_AUTH_TOKEN</code>, and the organization\nuid as <code>REMOTIVE_CLOUD_ORGANIZATION</code>. If you run with a RemotiveBroker license file, keep it\nout of the repository: store it as a secret too and point <code>REMOTIVEBROKER_LICENSE</code> at it.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"the-workflow\">The workflow<a href=\"https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci#the-workflow\" class=\"hash-link\" aria-label=\"Direct link to The workflow\" title=\"Direct link to The workflow\">​</a></h2>\n<p>With that in place, the job is four steps: install the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-cli/installation\">RemotiveCLI</a>, generate the\ntopology, start it with the tester profile, and clean up.</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># .github/workflows/topology-tests.yml</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> Topology tests</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">on</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">pull_request</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">jobs</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">topology-tests</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">runs-on</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ubuntu</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">latest</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">env</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:#00a4db\">REMOTIVE_CLOUD_AUTH_TOKEN</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"> secrets.REMOTIVE_CLOUD_AUTH_TOKEN </span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:#00a4db\">REMOTIVE_CLOUD_ORGANIZATION</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"> secrets.REMOTIVE_CLOUD_ORGANIZATION </span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">steps</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">uses</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> actions/checkout@v4</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> Install RemotiveCLI</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">run</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> pipx install remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">cli</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> Generate topology</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">run</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive topology generate </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">n mytopology </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">f topology/mytopology.instance.yaml build</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> Run tests</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">run</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">&gt;</span><span class=\"token scalar string\" style=\"color:#e3116c\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token scalar string\" style=\"color:#e3116c\">          docker compose -f build/mytopology/docker-compose.yml --profile tester</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token scalar string\" style=\"color:#e3116c\">          up --abort-on-container-exit --exit-code-from tester</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:#00a4db\">name</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> Clean up</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">if</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> always()</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">run</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> docker compose </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">f build/mytopology/docker</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">compose.yml </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">profile tester down</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>--abort-on-container-exit</code> is what makes this work in CI: when pytest finishes, the tester\ncontainer exits and docker compose stops the rest of the topology. Adding\n<code>--exit-code-from tester</code>, a plain docker compose option, makes the step's exit code pytest's,\nso a failing test fails the job. The <code>down</code> step runs even after a failure, so the runner is\nleft clean.</p>\n<p>Generate runs on every job, and that's on purpose: the generated files are completely\noverwritten each time, and any change to the platform or instance files needs a new\ngenerate anyway. Don't commit <code>build/</code>.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"when-it-goes-red\">When it goes red<a href=\"https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci#when-it-goes-red\" class=\"hash-link\" aria-label=\"Direct link to When it goes red\" title=\"Direct link to When it goes red\">​</a></h2>\n<p>Most failures are easier to read in the container logs than in the pytest output alone. Add\na step with <code>if: failure()</code> that runs <code>docker compose -f build/mytopology/docker-compose.yml logs</code>\nbefore the clean-up, and you get the behavioral models' and brokers' side of the story too.\nThe <a href=\"https://developer.remotivelabs.com/docs/remotive-topology/tools/docker\">Docker tips</a> page has\nmore commands for following logs per service.</p>\n<p>To reproduce locally, run the same <code>generate</code>, then start the topology without the tester\nprofile, as described in\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/running\">Running a topology</a>, and\nrun pytest from your editor against <code>localhost:50051</code>. Same tests, same topology, just with a\ndebugger attached.</p>",
            "url": "https://developer.remotivelabs.com/blog/2026/08/20/topologies-in-ci",
            "title": "Running topologies in CI",
            "summary": "Start a RemotiveTopology in a GitHub Actions job, run pytest against it, and tear it down again.",
            "date_modified": "2026-08-20T00:00:00.000Z",
            "author": {
                "name": "Ola Nilsson"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/07/29/restbus-dashboard",
            "content_html": "<p>An ECU on its own rarely behaves the way it does in the car. It expects to hear its\nneighbors: periodic frames that say the ignition is on, the speed is zero, the doors are\nclosed. This post sets up a basic restbus that sends those frames for you, and a\nRemotiveStudio dashboard where you can see them and change values while everything runs.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"what-a-restbus-is-for\">What a restbus is for<a href=\"https://developer.remotivelabs.com/blog/2026/07/29/restbus-dashboard#what-a-restbus-is-for\" class=\"hash-link\" aria-label=\"Direct link to What a restbus is for\" title=\"Direct link to What a restbus is for\">​</a></h2>\n<p>A restbus simulates \"the rest of the bus\": every frame your device under test expects\nfrom ECUs that aren't there. Most of these frames are cyclic, so the simulation has to\nkeep sending them at the right cycle time, or the device starts logging timeouts and\nfalling back to safe states.</p>\n<p>In RemotiveTopology this usually starts with an\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/concepts\">ECU mock</a>. A mock is the\nsimpler alternative to a behavioral model: it doesn't decide anything on its own, it\njust provides a restbus that emulates the ECU, and something else (often a test case,\ntoday it's us) decides what it sends. If the code that controls a mock gets complicated,\nthat's a sign it should become a behavioral model instead.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"setting-up-the-restbus\">Setting up the restbus<a href=\"https://developer.remotivelabs.com/blog/2026/07/29/restbus-dashboard#setting-up-the-restbus\" class=\"hash-link\" aria-label=\"Direct link to Setting up the restbus\" title=\"Direct link to Setting up the restbus\">​</a></h2>\n<p>Start from a platform with a CAN channel, and instantiate the ECU you want to stand in\nfor with a mock. The\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/instance\">instance docs</a> use\na body controller on two CAN buses; mocking it on just one of them looks like this:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">instance</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.15</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">platform</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">includes</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ./topology.platform.yaml</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">ecus</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">BCM</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">mock</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:#00a4db\">channels</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        DriverCan0</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Leave out <code>channels</code> (<code>mock: {}</code>) to mock the ECU on every channel it is connected to.\nThen generate the topology and start it in interactive mode, so it keeps running while\nyou work, as described in\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/running\">Running a topology</a>:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology generate </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> mytopology.instance.yaml build</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:#d73a49\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> build/mytopology/docker-compose.yml up</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>The broker inside the topology is forwarded to <code>http://localhost:50051</code>. Each ECU's view\nof a channel is a namespace named <code>&lt;ECU&gt;-&lt;Channel&gt;</code>, so here it's <code>BCM-DriverCan0</code>. If\nyou're unsure, list them:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker signals namespaces </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--url</span><span class=\"token plain\"> http://localhost:50051</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Now tell the broker which frames to send. The\n<a href=\"https://developer.remotivelabs.com/docs/remotive-cli/cli_man_pages#remotive-broker-restbus\"><code>remotive broker restbus</code></a>\ncommands follow a simple workflow: add, start, update, and stop or reset. Pick a frame\nfrom your signal database (the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/topology/signal-view\">signal view</a>\nin RemotiveStudio is a quick way to browse them); <code>BodyStatus</code> below is a stand-in name:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker restbus </span><span class=\"token function\" style=\"color:#d73a49\">add</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--frame</span><span class=\"token plain\"> BCM-DriverCan0:BodyStatus --cycle-time </span><span class=\"token number\" style=\"color:#36acaa\">100</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker restbus start </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--namespace</span><span class=\"token plain\"> BCM-DriverCan0</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>--cycle-time</code> is in milliseconds and overrides the cycle time from the database; leave\nit out to use the database value. <code>add --start</code> registers and starts in one go.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"building-the-dashboard\">Building the dashboard<a href=\"https://developer.remotivelabs.com/blog/2026/07/29/restbus-dashboard#building-the-dashboard\" class=\"hash-link\" aria-label=\"Direct link to Building the dashboard\" title=\"Direct link to Building the dashboard\">​</a></h2>\n<p>Start RemotiveStudio on the workspace that holds your topology files, as in\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/getting-started\">Getting started</a>:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive studio </span><span class=\"token builtin class-name\">.</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>The <a href=\"https://developer.remotivelabs.com/docs/remotive-studio/dashboard\">dashboard</a> needs a\nrunning topology to connect to; without one it shows \"RemotiveTopology unavailable\".\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/dashboard/create-dashboard\">Create a dashboard</a>\nfrom the <strong>Topology</strong> sidebar panel, then use <strong>Add Panel</strong> to\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/dashboard/add-panel\">add panels</a>.\nFor a restbus, three are useful:</p>\n<ul>\n<li><strong>Frame distribution</strong> shows which frames arrive and how often, so you can see at a\nglance that the restbus is running and at roughly the cycle time you asked for.</li>\n<li><strong>Trace</strong> shows each frame as it arrives, with its raw bytes, and the signal values\nwhen you expand a row.</li>\n<li><strong>Time series</strong> plots the signals you select, which is where you'll see your changes.</li>\n</ul>\n<p>Use the signal selection button to pick signals for the time series panel. A new\ndashboard is a draft until you click <strong>Save As</strong>; it's then stored as a\n<code>.dashboard.json</code> file in your workspace, so you can commit it next to the topology and\nopen it again from the <strong>Files</strong> sidebar.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"changing-values-while-it-runs\">Changing values while it runs<a href=\"https://developer.remotivelabs.com/blog/2026/07/29/restbus-dashboard#changing-values-while-it-runs\" class=\"hash-link\" aria-label=\"Direct link to Changing values while it runs\" title=\"Direct link to Changing values while it runs\">​</a></h2>\n<p>With frames flowing, change what the restbus sends. <code>update</code> sets the values it emits\nfrom now on; give several comma-separated values and the restbus loops over them.\nFor example, a door signal that reads open on every fourth value:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker restbus update </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--signal</span><span class=\"token plain\"> BCM-DriverCan0:DoorOpen:0,0,0,1</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Use <code>--initial</code> for values that should be sent once before the loop starts. The time\nseries panel follows along as soon as the new values go out, and the trace panel shows\nwhat changed in the raw bytes. To pause, run <code>stop</code>; the configuration stays, so <code>start</code>\npicks up where you left off. <code>remove --frame</code> drops a single frame, and <code>reset</code> clears\neverything for a namespace.</p>\n<p>Here the dashboard is the place you watch, and the terminal next to it is where you\nturn the knobs. The same restbus can be controlled from code, too: the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/apis\">RemotiveTopology framework</a>\nis a Python library for writing test cases and behavioral models against the same\nnamespaces, which is where to go once a sequence of <code>update</code> commands starts to feel\nlike a script.</p>",
            "url": "https://developer.remotivelabs.com/blog/2026/07/29/restbus-dashboard",
            "title": "A basic restbus, watched from a dashboard",
            "summary": "Simulate the rest of the network's periodic frames with a restbus, then change signal values while it runs and watch the result in a RemotiveStudio dashboard.",
            "date_modified": "2026-07-29T00:00:00.000Z",
            "author": {
                "name": "Ola Nilsson"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python",
            "content_html": "<p>If someone on your team already models a system in a simulation tool, you probably don't want\nto rewrite that model by hand as an ECU. With the <code>fmu</code> module in the RemotiveTopology Python\nframework you can load the exported FMU, connect it to the signals on your virtual buses, and\nrun it as a behavioral model next to everything else in the topology.</p>\n<div class=\"theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary\"><div class=\"admonitionHeading_Gvgb\"><span class=\"admonitionIcon_Rf37\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>TODO</div><div class=\"admonitionContent_BuS1\"><p>Also needed in the docs: once this post is written, add (or link to) a matching how-to page under docs/remotive-topology.</p></div></div>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"what-an-fmu-is-and-when-you-would-use-one\">What an FMU is and when you would use one<a href=\"https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python#what-an-fmu-is-and-when-you-would-use-one\" class=\"hash-link\" aria-label=\"Direct link to What an FMU is and when you would use one\" title=\"Direct link to What an FMU is and when you would use one\">​</a></h2>\n<p>A Functional Mock-up Unit is a packaged simulation model, following the FMI standard, that\nmany modeling tools can export. It's a zip file with a model description (the inputs,\noutputs and default experiment settings) and the compiled model.</p>\n<p>In RemotiveTopology, an FMU is one of the supported kinds of\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/concepts\">behavioral model</a>, next to\nplain Python and Synopsys Silver. A behavioral model emulates the behavior of a real ECU, so\nan FMU is a good fit when the behavior you need already exists as a physics or control\nmodel: vehicle dynamics, a battery, a thermal system, or the classic bouncing ball. Instead\nof hard-coding values in a mock, the model reacts to what's on the bus and produces\nrealistic outputs.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"prerequisites\">Prerequisites<a href=\"https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python#prerequisites\" class=\"hash-link\" aria-label=\"Direct link to Prerequisites\" title=\"Direct link to Prerequisites\">​</a></h2>\n<p>You need a working RemotiveTopology setup, as described in\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/install\">Install</a>: Docker (or Podman),\nRemotiveCLI with an active subscription, and Python 3.10 or later for behavioral models.</p>\n<p>The FMU support lives in the <code>remotivelabs-topology</code> package behind an extra, since it pulls\nin <code>fmpy</code> and <code>numpy</code>:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">pip </span><span class=\"token function\" style=\"color:#d73a49\">install</span><span class=\"token plain\"> remotivelabs-topology</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">fmu</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Then the FMU itself. The framework drives the model one step at a time, so it needs to be:</p>\n<ul>\n<li>an FMI 2.0 or 3.0 <strong>Co-Simulation</strong> FMU,</li>\n<li>configured with a fixed step size and no internal solver,</li>\n<li>carrying a <code>defaultExperiment</code> in its model description (that's where the step size is read from).</li>\n</ul>\n<p>If the FMU doesn't support co-simulation or lacks a default experiment, loading it fails\nwith an error straight away, which is a nice early warning.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"loading-the-fmu-from-python\">Loading the FMU from Python<a href=\"https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python#loading-the-fmu-from-python\" class=\"hash-link\" aria-label=\"Direct link to Loading the FMU from Python\" title=\"Direct link to Loading the FMU from Python\">​</a></h2>\n<p>The entry point is <code>FMUSimulation</code>. Give it a path, and it reads the model description,\ninstantiates the FMU and resets it to its initial state:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> pathlib </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> Path</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">fmu </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> FMUSimulation</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">fmu </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> FMUSimulation</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">Path</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"speed_model.fmu\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">fmu</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># dump model information and variables</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">fmu</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">step_size</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">fmu</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">input_var_names</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">fmu</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">output_var_names</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p><code>print()</code> is the first thing I run on any new FMU: it shows the variable names you'll need\nin the next step. The step size comes from the default experiment, but you can override it\nwith <code>FMUSimulation(path, step_size=0.01)</code>.</p>\n<p>Each call to <code>await fmu.step()</code> advances the simulation by one step, applies the current\ninputs and returns the outputs. You can also set an input directly with\n<code>fmu.set_input_value(\"name\", value)</code>; it sticks for all future steps, and an unknown name\nraises a <code>ValueError</code>.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"mapping-fmu-inputs-and-outputs-to-signals\">Mapping FMU inputs and outputs to signals<a href=\"https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python#mapping-fmu-inputs-and-outputs-to-signals\" class=\"hash-link\" aria-label=\"Direct link to Mapping FMU inputs and outputs to signals\" title=\"Direct link to Mapping FMU inputs and outputs to signals\">​</a></h2>\n<p>The <code>FMUBehavioralModel</code> class connects an <code>FMUSimulation</code> to the topology. Inputs are\ndescribed with an <code>InputMapping</code>, a nested dictionary from namespace, to frame, to signal,\nto FMU input name. Namespaces are named <code>&lt;ECU&gt;-&lt;Channel&gt;</code>, as described in\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/instance\">Instantiating a topology</a>.</p>\n<p>In this example (the ECU, frame and variable names are made up), the FMU gets its\n<code>accelerator_pedal</code> input from a signal on <code>ChassisCan0</code>:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">fmu </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> InputMapping</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">input_mapping</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> InputMapping </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel-ChassisCan0\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token string\" style=\"color:#e3116c\">\"PedalStatus\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token string\" style=\"color:#e3116c\">\"AcceleratorPedalPosition\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"accelerator_pedal\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Whenever a matching frame arrives, the model writes the signal value to the FMU input.\nValues outside the signal's min and max from the signal database are ignored, so a bad\nframe doesn't push the model into nonsense.</p>\n<p>Outputs go the other way. <code>FMUSimulation</code> takes an <code>on_output</code> callback that runs after\nevery step with a dictionary of output values. A simple way to put them on the bus is to\nlet a restbus send the ECU's frames and update their signals from the callback:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">namespaces </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> filters</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">namespaces</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">can </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> CanNamespace</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> RestbusConfig</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">chassis_can </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> CanNamespace</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel-ChassisCan0\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    restbus_configs</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">RestbusConfig</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">filters</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">SenderFilter</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">ecu_name</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">on_output</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">outputs</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> chassis_can</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">restbus</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">update_signals</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"VehicleSpeed\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> outputs</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token string\" style=\"color:#e3116c\">\"vehicle_speed\"</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"running-it-as-part-of-a-topology\">Running it as part of a topology<a href=\"https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python#running-it-as-part-of-a-topology\" class=\"hash-link\" aria-label=\"Direct link to Running it as part of a topology\" title=\"Direct link to Running it as part of a topology\">​</a></h2>\n<p>Putting it together, the model script looks much like any other behavioral model.\n<code>run_forever()</code> starts a ticker at the FMU's step size, steps the simulation on every tick\nand handles inputs and control requests at the same time:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> asyncio</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> pathlib </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> Path</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">broker </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> BrokerClient</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">cli</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">behavioral_model </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> BehavioralModelArgs</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">fmu </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> FMUBehavioralModel</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> FMUSimulation</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">namespaces </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> filters</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">namespaces</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">can </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> CanNamespace</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> RestbusConfig</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">main</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">args</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> BehavioralModelArgs</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">with</span><span class=\"token plain\"> BrokerClient</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">url</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">args</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> auth</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">args</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">auth</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">as</span><span class=\"token plain\"> broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        chassis_can </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> CanNamespace</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel-ChassisCan0\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            restbus_configs</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">RestbusConfig</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">filters</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">SenderFilter</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">ecu_name</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">on_output</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">outputs</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> chassis_can</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">restbus</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">update_signals</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"VehicleSpeed\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> outputs</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token string\" style=\"color:#e3116c\">\"vehicle_speed\"</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        fmu </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> FMUSimulation</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">Path</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"speed_model.fmu\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> on_output</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">on_output</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">with</span><span class=\"token plain\"> FMUBehavioralModel</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            fmu</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">fmu</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            input_mapping</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">                </span><span class=\"token string\" style=\"color:#e3116c\">\"SpeedModel-ChassisCan0\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">                    </span><span class=\"token string\" style=\"color:#e3116c\">\"PedalStatus\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token string\" style=\"color:#e3116c\">\"AcceleratorPedalPosition\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"accelerator_pedal\"</span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            broker_client</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            namespaces</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">chassis_can</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">as</span><span class=\"token plain\"> bm</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> bm</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">run_forever</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">if</span><span class=\"token plain\"> __name__ </span><span class=\"token operator\" style=\"color:#393A34\">==</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"__main__\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    asyncio</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">run</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">main</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">BehavioralModelArgs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">parse</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>A bonus you get for free: when the model receives a reboot request, it resets the FMU to its\ninitial state along with the restbuses, so a test can start every case from a known state.</p>\n<p>In the instance file, the model is added to its ECU like any Python behavioral model:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">ecus</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">SpeedModel</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">models</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:#00a4db\">speed_model</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> python</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">include</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ../ecus</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">main</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> speed_model</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>The container that runs Python models needs the <code>fmu</code> extra installed, so add it to the\nimage or Dockerfile you configure under <code>settings.docker.python</code>. Then generate and start the\ntopology as usual:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology generate </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> mytopology.instance.yaml build</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:#d73a49\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:#36acaa\">-f</span><span class=\"token plain\"> build/mytopology/docker-compose.yml up</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>If the signals don't show up, check the namespace names first:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker signals namespaces </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--url</span><span class=\"token plain\"> http://localhost:50051</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"where-to-go-next\">Where to go next<a href=\"https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python#where-to-go-next\" class=\"hash-link\" aria-label=\"Direct link to Where to go next\" title=\"Direct link to Where to go next\">​</a></h2>\n<ul>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/instance\">Instantiating a topology</a>: behavioral models, mocks and Docker settings.</li>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/running\">Running a topology</a>: generating, interactive mode and running tests.</li>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/apis\">API and client library</a>: the full Python API reference, including the <code>fmu</code> module.</li>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/examples\">Examples</a>: the examples repository, a good place to start from a working setup.</li>\n</ul>",
            "url": "https://developer.remotivelabs.com/blog/2026/07/08/fmu-integration-python",
            "title": "Integrating an FMU with Python",
            "summary": "Run a Functional Mock-up Unit (FMU) as a behavioral model in RemotiveTopology, with a few lines of Python that map bus signals to FMU inputs and outputs.",
            "date_modified": "2026-07-08T00:00:00.000Z",
            "author": {
                "name": "Albin Theander"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/06/24/named-values-studio-python",
            "content_html": "<p>A gear lever signal that reads <code>3</code> doesn't tell you much. Your signal database usually\nknows that <code>3</code> means <code>DRIVE</code>, and RemotiveStudio and the Python libraries can use that\nknowledge. This post shows where named values live and how to work with them in both.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"what-named-values-are\">What named values are<a href=\"https://developer.remotivelabs.com/blog/2026/06/24/named-values-studio-python#what-named-values-are\" class=\"hash-link\" aria-label=\"Direct link to What named values are\" title=\"Direct link to What named values are\">​</a></h2>\n<p>Many signals don't carry a measurement. They carry a state: a door is open or closed, a\ngear is in park or drive, a lamp is off, on or failing. On the bus these states are plain\nintegers, and the signal database maps each integer to a name. In a DBC file this is the\nvalue table for the signal; ARXML and LDF have their own ways of describing the same thing.\nThink of it as an enum attached to a signal.</p>\n<p>RemotiveLabs calls these mappings <strong>named values</strong>. They come straight from the signal\ndatabases your topology references (DBC, ARXML, LDF, Fibex, see the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/topology\">supported file formats</a>), so\nyou don't define them anywhere else. If the database has them, you can use them.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"finding-named-values-in-remotivestudio\">Finding named values in RemotiveStudio<a href=\"https://developer.remotivelabs.com/blog/2026/06/24/named-values-studio-python#finding-named-values-in-remotivestudio\" class=\"hash-link\" aria-label=\"Direct link to Finding named values in RemotiveStudio\" title=\"Direct link to Finding named values in RemotiveStudio\">​</a></h2>\n<p>The quickest way to see what a database defines is the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-studio/topology/signal-view\">Signal view</a> in\nRemotiveStudio:</p>\n<ol>\n<li>Open the file tree with <strong>Files</strong> and click your <code>.instance.yaml</code>, <code>.platform.yaml</code>, or\na database file directly.</li>\n<li>Click the bar-chart icon in the segmented control at the top of the topology viewer.</li>\n<li>Find the frame you care about. The search bar filters both frames and signals.</li>\n<li>Click the frame row to expand its signals. Each signal shows its unit, min/max, factor\nand offset, receivers, and its named values.</li>\n</ol>\n<p>The first time you open the Signal view, RemotiveStudio indexes the signal databases, so\ngive it a moment on large ARXML files. Today the Signal view covers CAN and LIN signals.</p>\n<p>This is also a good way to check a database before you write code against it. If you\nexpect <code>GearPosition</code> to have named values and the Signal view shows none, the database\nyou're using doesn't have them, and no code will fix that.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"reading-named-values-from-python\">Reading named values from Python<a href=\"https://developer.remotivelabs.com/blog/2026/06/24/named-values-studio-python#reading-named-values-from-python\" class=\"hash-link\" aria-label=\"Direct link to Reading named values from Python\" title=\"Direct link to Reading named values from Python\">​</a></h2>\n<p>The <a href=\"https://developer.remotivelabs.com/apis/python/remotivelabs/broker\" target=\"_blank\" rel=\"noopener noreferrer\">RemotiveBroker Python API</a>\nexposes the mapping on every <code>SignalInfo</code> in two directions: <code>named_values</code> maps raw\nintegers to names, and <code>value_names</code> maps names back to integers. Here is a small script,\nadapted from the API docs, that prints both for one signal. The <code>DriverCan</code> namespace and\nthe <code>GearData.GearPosition</code> signal are examples; use your own.</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> asyncio</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">broker </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> BrokerClient</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">def</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:#d73a49\">main</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:#393A34\">-</span><span class=\"token operator\" style=\"color:#393A34\">&gt;</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:#36acaa\">None</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">with</span><span class=\"token plain\"> BrokerClient</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">url</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token string\" style=\"color:#e3116c\">\"http://127.0.0.1:50051\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">as</span><span class=\"token plain\"> broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        info </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">get_signal_info</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"GearData.GearPosition\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"DriverCan\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">if</span><span class=\"token plain\"> info </span><span class=\"token keyword\" style=\"color:#00009f\">is</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:#36acaa\">None</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:#00009f\">raise</span><span class=\"token plain\"> SystemExit</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"Signal not found in DriverCan\"</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">info</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">named_values</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># raw value -&gt; name, e.g. {0: \"PARK\", 3: \"DRIVE\"}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">info</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">value_names</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># name -&gt; raw value, e.g. {\"PARK\": 0, \"DRIVE\": 3}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">if</span><span class=\"token plain\"> __name__ </span><span class=\"token operator\" style=\"color:#393A34\">==</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:#e3116c\">\"__main__\"</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    asyncio</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">run</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">main</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>If you're not sure which namespaces exist on a running topology, list them first:</p>\n<div class=\"language-sh codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-sh codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive broker signals namespaces </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--url</span><span class=\"token plain\"> http://localhost:50051</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>When you subscribe, you can have the client decode values for you. Pass\n<code>decode_named_values=True</code> to <code>subscribe_frames</code>, and integer values that have a mapping\narrive as their names in <code>frame.signals</code>:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">stream </span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">subscribe_frames</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"DriverCan\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token string\" style=\"color:#e3116c\">\"GearData\"</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    decode_named_values</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token boolean\" style=\"color:#36acaa\">True</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">async</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:#00009f\">for</span><span class=\"token plain\"> frame </span><span class=\"token keyword\" style=\"color:#00009f\">in</span><span class=\"token plain\"> stream</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:#00009f\">print</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">frame</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">signals</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># {\"GearData.GearPosition\": \"DRIVE\", ...}</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>To write a state, look up the raw value with <code>value_names</code> and publish that integer:</p>\n<div class=\"language-python codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-python codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token keyword\" style=\"color:#00009f\">from</span><span class=\"token plain\"> remotivelabs</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">broker </span><span class=\"token keyword\" style=\"color:#00009f\">import</span><span class=\"token plain\"> WriteSignal</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:#00009f\">await</span><span class=\"token plain\"> broker_client</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">publish</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token string\" style=\"color:#e3116c\">\"DriverCan\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token plain\">WriteSignal</span><span class=\"token punctuation\" style=\"color:#393A34\">(</span><span class=\"token plain\">name</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token string\" style=\"color:#e3116c\">\"GearData.GearPosition\"</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"> value</span><span class=\"token operator\" style=\"color:#393A34\">=</span><span class=\"token plain\">info</span><span class=\"token punctuation\" style=\"color:#393A34\">.</span><span class=\"token plain\">value_names</span><span class=\"token punctuation\" style=\"color:#393A34\">[</span><span class=\"token string\" style=\"color:#e3116c\">\"PARK\"</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">]</span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><span class=\"token punctuation\" style=\"color:#393A34\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:#393A34\">)</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>The same lookup works when you set restbus signals with <code>RestbusSignalConfig.set(...)</code>.\nIf you write behavioral models or tests with the\n<a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/apis\">RemotiveTopology framework</a>,\nyou're using the same broker client underneath, so <code>SignalInfo.named_values</code> and\n<code>value_names</code> are available there too.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"common-pitfalls\">Common pitfalls<a href=\"https://developer.remotivelabs.com/blog/2026/06/24/named-values-studio-python#common-pitfalls\" class=\"hash-link\" aria-label=\"Direct link to Common pitfalls\" title=\"Direct link to Common pitfalls\">​</a></h2>\n<ul>\n<li><strong>The value type changes.</strong> With <code>decode_named_values=True</code>, a signal that used to be an\n<code>int</code> becomes a <code>str</code>. Code that compares with <code>== 3</code> or does arithmetic on the value\nsilently stops matching. Pick one style per script and stick to it.</li>\n<li><strong>Not every value has a name.</strong> Only integers that appear in the mapping are decoded.\nA value outside the table, such as a reserved or error code, still arrives as an <code>int</code>,\nso handle both types, or look values up yourself with <code>info.named_values.get(value, value)</code>.</li>\n<li><strong>Decoding is off by default.</strong> <code>subscribe_frames</code> doesn't decode unless you ask, and\nthe frame handlers in the RemotiveTopology framework take a <code>decode_named_values</code>\nargument that is also off by default. If you see numbers where you expected names,\ncheck this first.</li>\n<li><strong>Names belong to a database.</strong> Two databases can map the same signal differently, for\nexample a channel DBC and an ECU extract. Check the Signal view for the topology you\nactually run, and look names up with <code>value_names</code> instead of hard-coding the integers.</li>\n<li><strong>Typos fail late.</strong> <code>info.value_names[\"Park\"]</code> raises a <code>KeyError</code> when the database says\n<code>PARK</code>. Copy names from the Signal view rather than from memory.</li>\n</ul>\n<p>Named values are a small feature, but they make logs, dashboards and test assertions much\neasier to read. For more on the APIs, see\n<a href=\"https://developer.remotivelabs.com/docs/remotive-broker/apis\">APIs and client libraries</a>.</p>",
            "url": "https://developer.remotivelabs.com/blog/2026/06/24/named-values-studio-python",
            "title": "Named values in RemotiveStudio and Python",
            "summary": "What named values are, where to find them in RemotiveStudio, and how to read and write them from Python.",
            "date_modified": "2026-06-24T00:00:00.000Z",
            "author": {
                "name": "Ola Nilsson"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization",
            "content_html": "<p>When a topology grows past a handful of files, it gets hard to say what's actually in it.\nWhich ECUs does that DBC bring in? What does the instance run in the end? This post walks\nthrough a small example and shows two ways to see the answer: <code>remotive topology show</code> in\nthe terminal, and the topology viewer in RemotiveStudio.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"the-example-topology\">The example topology<a href=\"https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization#the-example-topology\" class=\"hash-link\" aria-label=\"Direct link to The example topology\" title=\"Direct link to The example topology\">​</a></h2>\n<p>We start with a platform that has two CAN channels, each described by a DBC file. DBC files\ndon't say which channel they describe, so the platform file names the channels and points\neach one at its database:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># topology.platform.yaml</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">platform</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.15</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">channels</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">DriverCan0</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> can</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">database</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ../databases/driver_can.dbc</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">BodyCan0</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> can</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">database</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ../databases/body_can.dbc</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>That's the whole file, but it describes more than it seems to. The ECUs come from the DBCs:\nSCCM and BCM are on <code>DriverCan0</code>, and BCM, DIM, FLCM, RLCM and GWM are on <code>BodyCan0</code>. BCM\nsits on both buses.</p>\n<p>On top of that we write an instance, which says which part of the platform to run. Here we\nwant BCM with a Python behavioral model, and FLCM as a mock:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token comment\" style=\"color:#999988;font-style:italic\"># main.instance.yaml</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">instance</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.15</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">platform</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">includes</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ./topology.platform.yaml</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">ecus</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">BCM</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">models</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:#00a4db\">bcm</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">type</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> python</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">include</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> ../ecus</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:#00a4db\">main</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> bcm</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:#00a4db\">FLCM</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:#00a4db\">mock</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:#393A34\">{</span><span class=\"token punctuation\" style=\"color:#393A34\">}</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"looking-at-it-from-the-terminal\">Looking at it from the terminal<a href=\"https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization#looking-at-it-from-the-terminal\" class=\"hash-link\" aria-label=\"Direct link to Looking at it from the terminal\" title=\"Direct link to Looking at it from the terminal\">​</a></h2>\n<p>Before opening any UI, I like to ask the CLI what it sees. Both files live in <code>topology/</code>,\nnext to <code>databases/</code> and <code>ecus/</code>. Set up a workspace at the root of the project first, so\nrelative includes like <code>../databases</code> resolve the same way from every subfolder:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token builtin class-name\">cd</span><span class=\"token plain\"> my_project</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology workspace init</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Then show the platform:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology show platform topology/topology.platform.yaml</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>This prints the platform as <code>platform.yaml</code>, with everything the DBCs added filled in.\nEach ECU lists the channels it's connected to, and each ECU channel gets a <code>database</code> too,\nbecause that's the database the ECU uses to decode signals. If an ECU name isn't what you\nexpected, this is where you find out, before you write an instance that refers to it.</p>\n<p>For the instance, use <code>show instance</code>:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive topology show instance topology/main.instance.yaml</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>This shows only the parts of the platform that are instantiated, plus any defaults that\nwere applied. In our case, SCCM, DIM, RLCM and GWM are gone. BCM keeps both channels,\nbecause by default an ECU gets every channel it's connected to. FLCM's mock covers every\nchannel FLCM is on, which here is just <code>BodyCan0</code>.</p>\n<p>A few options are handy here:</p>\n<ul>\n<li><code>--full-platform</code> shows the full platform, not just the instance-specific parts.</li>\n<li><code>--check</code> checks the topology.</li>\n<li><code>--json</code> switches the output from YAML to JSON, and <code>-o</code> writes it to a file, which is\nuseful if you want to diff the resolved instance between two branches.</li>\n</ul>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"opening-it-in-remotivestudio\">Opening it in RemotiveStudio<a href=\"https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization#opening-it-in-remotivestudio\" class=\"hash-link\" aria-label=\"Direct link to Opening it in RemotiveStudio\" title=\"Direct link to Opening it in RemotiveStudio\">​</a></h2>\n<p>YAML is precise, but a tree is quicker to read. RemotiveStudio comes with RemotiveCLI and\nstarts from the same workspace:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive studio </span><span class=\"token builtin class-name\">.</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Open <strong>Files</strong> in the sidebar and click <code>topology.platform.yaml</code>. The topology viewer has\nthree modes, chosen with the segmented control at the top:</p>\n<ul>\n<li><strong>Tree view</strong> shows the platform as two top-level groups, <strong>Channels</strong> and <strong>ECUs</strong>.\nExpand <code>BodyCan0</code> to see the five ECUs on it, or expand BCM to see that it's on both\nbuses. Click a node to open its details, such as channel type, database path and\nconnected ECUs.</li>\n<li><strong>YAML view</strong> shows the resolved topology, with includes merged. It's read-only, and\nroughly what <code>remotive topology show platform</code> prints.</li>\n<li><strong>Signal view</strong> is a searchable table of every frame in the topology's CAN and LIN\ndatabases. Click a frame to see its signals, with units, min and max values, receivers\nand named values.</li>\n</ul>\n<p>Now open <code>main.instance.yaml</code>. The instance tree has the same channels and ECUs, cut down\nto what the instance runs, and adds instance-level entries such as the <code>bcm</code> behavioral\nmodel. Comparing the two trees side by side is the fastest way I know to check that an\ninstance contains what I meant it to.</p>\n<p>Studio opens DBC, ARXML, LDF and Fibex files directly too, by converting them to\n<code>.platform.yaml</code> first. Clicking an ECU extract is a quick way to see what's in it\nbefore you include it anywhere.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"tips-for-larger-platforms\">Tips for larger platforms<a href=\"https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization#tips-for-larger-platforms\" class=\"hash-link\" aria-label=\"Direct link to Tips for larger platforms\" title=\"Direct link to Tips for larger platforms\">​</a></h2>\n<p>Real platforms are rarely one file. They're usually a top-level <code>platform.yaml</code> that\nincludes subsystems:</p>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token key atrule\" style=\"color:#00a4db\">schema</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"> remotive</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">topology</span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\">platform</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token number\" style=\"color:#36acaa\">0.15</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:#00a4db\">includes</span><span class=\"token punctuation\" style=\"color:#393A34\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ./lighting.platform.yaml</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ./climate.platform.yaml</span><br></span><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:#393A34\">-</span><span class=\"token plain\"> ./driver.platform.yaml</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>Some things that help when there are many of them:</p>\n<ul>\n<li>Show each subsystem on its own first. If <code>lighting.platform.yaml</code> looks right by itself,\nyou've narrowed down where a problem in the combined platform can be.</li>\n<li>Use the tree view's search bar instead of expanding everything. \"Collapse all\" helps\nwhen you've lost track.</li>\n<li>Studio doesn't pick up edits to topology files until you reload the browser tab. The CLI\nalways reads the files fresh, so it's the better choice while you're editing.</li>\n<li>If a command complains about a missing ECU, run <code>show platform</code> on the file that should\ndefine it. It's often a spelling difference between two databases.</li>\n</ul>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"where-to-go-next\">Where to go next<a href=\"https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization#where-to-go-next\" class=\"hash-link\" aria-label=\"Direct link to Where to go next\" title=\"Direct link to Where to go next\">​</a></h2>\n<ul>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/platform\">Describing the platform</a>: DBC, ARXML, LDF and <code>platform.yaml</code> includes.</li>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/usage/instance\">Instantiating topology</a>: choosing ECUs and channels, models and mocks.</li>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-studio/topology\">Topology in RemotiveStudio</a> and its <a href=\"https://developer.remotivelabs.com/docs/remotive-studio/topology/tree\">tree view</a>.</li>\n<li><a href=\"https://developer.remotivelabs.com/docs/remotive-topology/workspace\">Workspace</a> and the <a href=\"https://developer.remotivelabs.com/docs/remotive-cli/cli_man_pages#remotive-topology-show\"><code>remotive topology show</code> reference</a>.</li>\n</ul>",
            "url": "https://developer.remotivelabs.com/blog/2026/06/10/topology-visualization",
            "title": "Visualizing a topology, platform and instance",
            "summary": "A worked example of looking at a RemotiveTopology platform and an instance built from it, with the CLI and in RemotiveStudio.",
            "date_modified": "2026-06-10T00:00:00.000Z",
            "author": {
                "name": "Filip Åhfelt"
            },
            "tags": []
        },
        {
            "id": "https://developer.remotivelabs.com/blog/2026/05/27/welcome",
            "content_html": "<p>This is where the RemotiveLabs team writes short, technical articles: worked examples,\npatterns we use ourselves, and the things that didn't fit in the\n<a href=\"https://developer.remotivelabs.com/\">documentation</a>.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"what-to-expect\">What to expect<a href=\"https://developer.remotivelabs.com/blog/2026/05/27/welcome#what-to-expect\" class=\"hash-link\" aria-label=\"Direct link to What to expect\" title=\"Direct link to What to expect\">​</a></h2>\n<p>Posts are hands-on and to the point. Expect topics like connecting simulation models to a\ntopology, working with signals from Python, and building dashboards in RemotiveStudio.</p>\n<p>When a post covers something you'll come back to, we link to the matching page in the\ndocs, which is where the reference material lives.</p>\n<h2 class=\"anchor anchorWithStickyNavbar_LWe7\" id=\"code-not-slides\">Code, not slides<a href=\"https://developer.remotivelabs.com/blog/2026/05/27/welcome#code-not-slides\" class=\"hash-link\" aria-label=\"Direct link to Code, not slides\" title=\"Direct link to Code, not slides\">​</a></h2>\n<p>Most posts include code you can copy and run:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#393A34;--prism-background-color:#f6f8fa\"><div class=\"codeBlockContent_biex\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#393A34;background-color:#f6f8fa\"><code class=\"codeBlockLines_e6Vv\"><span class=\"token-line\" style=\"color:#393A34\"><span class=\"token plain\">remotive </span><span class=\"token parameter variable\" style=\"color:#36acaa\">--help</span><br></span></code></pre><div class=\"buttonGroup__atx\"><button type=\"button\" aria-label=\"Copy code to clipboard\" title=\"Copy\" class=\"clean-btn\"><span class=\"copyButtonIcons_eSgA\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_y97N\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_LjdS\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div>\n<p>If you build something with RemotiveLabs and want to share it, reach out on\n<a href=\"https://github.com/remotivelabs\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub</a>.</p>",
            "url": "https://developer.remotivelabs.com/blog/2026/05/27/welcome",
            "title": "Welcome to the RemotiveLabs developer blog",
            "summary": "Short, technical articles from the people building RemotiveLabs.",
            "date_modified": "2026-05-27T00:00:00.000Z",
            "author": {
                "name": "Ola Nilsson"
            },
            "tags": []
        }
    ]
}