Developer Journey for digital.auto playground: Difference between revisions

Line 251: Line 251:


const plugin = ({widgets, simulator, vehicle}) => {
const plugin = ({widgets, simulator, vehicle}) => {
   widgets.register("testwidget", SignalPills([
   widgets.register("testwidget", SignalPills([{signal: "Vehicle.Body.Windshield.Rear.Wiping. vehicle))
                                              {
                                                signal: "Vehicle.Body.Windshield.Rear.Wiping.Intensity"
                                              }
                                            ],
                                            vehicle))
}
}



Revision as of 16:49, 1 June 2023

playground.digital.auto

This is the developer journey for the digital.auto playground. Here, you will learn how to create a basic prototype, how to customize it, and how to create re-usable widgets - including new UX elements and new data sources.

For a general introduction of digital.auto, please click here. For the documentation of the key architectural concepts of the digital.auto playground, please click architectural here

Introduction: Creating a simple prototype with re-usable widgets

Creating a new Prototype

Model selection screen


Developing your own Prototype starts with selecting a Model you want to develop the prototype for. Note that you can only develop Prototypes for Models which you were granted Contributor rights.




Create Prototype Button.png


If you have the appropriate rights the "New Prototype" button will be available in the Prototype overview of the Model.



Create Prototype dialogue.png


Klicking on this button will spawn a dialogue that enables a developer to enter a name and some basic info for the Customer Journey the name field is required but the rest can be left blank.



New Prototype in list.png


Your new Prototype will now appear in the overview

The Journey Tab

The "Journey" Tab of the Prototype contains the projected Customer Journey as well as some meta information. Here you can also Prototype is administrated . Here you can also rename the Prototype, add an image to represent the Prototype and delete the Prototype (if you have the rights to do so).



New Prototype Journey marked.png

Editable items in the Journey will have have a button with a pencil symbol for authorized Users (marked in red in the image above).

With the top left edit button you can add switch the image of the Prototype. Klicking on that button will open a menu to select an image from available media. please refer to the section Adding Media for more details.

With the top right button you can change the name of the prototype and the basic info like stakeholders and problems the Prototype is supposed to solve.

Below those parameters you find the parameter "Tags". These are used to filter Prototypes and are also displayed on the list of Prototypes of a Model. You can remove Tags by clicking on the 'x' next to the Tag and add a Tag by clicking on "Add New" and selecting the Tag category and then the Tag in the two consecutively appearing dropdowns and then clicking the checkmark to the right to confirm your selection.

Editing the Customer Journey

The customer Journey is a table intended to describe the customers journey in steps(column headings) with custom parameters in rows. The columns and row headings and their number can be configured freely.

The table is defined in a simple markup language. It works as follows:

#<column 1 header>
<row 1 header>: <cell 1/1>
<row n header>: <cell 1/n>

#<column n header>
<row 1 header>: <cell n/1>
<row n header>: <cell n/n>

the two screenshots below show an example of a Customer Journey and the respective markup. The corresponding parts are marked in the same color.

Customer Journey Marked.png

Customer Journey Code.png

The Code Tab

This is the area where you will actually work on the prototype itself. It is split into three sections:

The code editor: The left section is the code editor. This is where you write the actual code to the prototype. Prototype code is written in Python. The code will be compiled and run locally in your browser. so executions are independent from one another. Everyone who has access to the Prototype can run this code and (locally) modify it. If you have the approrpiate rights as a contributor for the Prototype then your changes are automatically saved. In order to run the code you have to switch to the the Dashboard. You can write regular Python code here but bear in mind that some io functions and some other basic things might not be supported. More details on Prototype code development in the following section Working with Prototype code

The API catalogue: In the top right section you find the API catalogue. This is a small version of the API catalogue of the current version. Here you can look up API nodes you might want to access. It features a search and filter function and clicking on a node will copy it to your clipboard.

The dashboard configuration: On the bottom right is the dashboard configuration. This is used to place Widgets on the dashboard.

[
	{
		"boxes": [1],
		"plugin": <plugin 1 name>,
		"widget": <plugin 1 widget 1 name>
	},
	{
		"boxes": [3,4],
		"plugin": <plugin 1 name>,
		"widget": <plugin 1 widget 2 name>
	},
	{
		"boxes": [5,10],
		"plugin": <plugin 2 name>,
		"widget": <plugin 2 widget 1 name>
	}
]

The code above is a template to create a valid Dashboard configuration. The config is a JSON list of objects each defining the placement of a certain widget. Since Widgets are bound to Plugins you have to name the Plugin as it is named in the Plugin list and the name of the Widget as defined inside that Plugin. The names must be written in quotes without the angle brackets. The "boxes" parameter defines which box(es) the Widget will occupy on the gridview of the Dashboard. It is a comma separated list. You can use any boxes in combination or alone as long as they form a rectangular shape.

Working with Prototype code

As stated above you can technically write any Python code with limitations. A lot of the ressources a Python implementation expects are emulated but not everything might work. Also right now there is no way to import external libraries. This is due to how the code is handled. A complete list of supported packages as well as packages specific to browser based Python can be found here.

When developing your Prototype you mostly interact with two things: The VSS API and the Plugins.

Access to VSS APIs: This is achieved via the Vehicle class of the Playground native sdv_model package.

from sdv_model import Vehicle
vehicle = Vehicle()

The code above demonstrates the Vehicle class being imported and instantiated. Here and in further examples we are using lowercase vehicle as a variable name but you can use any name you like. Access to API nodes works like accessing an object. You can read values from API nodes for sensors:

await vehicle.Acceleration.Longitudinal.get()

You can set values to API nodes for actuators: Note: Values can be integers, decimal numbers, booleans or attributes from VSS depending on the actuator.

await vehicle.Body.Mirrors.Right.Tilt.set(45)


You can subscribe to value changes:

await vehicle.Speed.subscribe(run_simulation)


Please note that all API nodes must be called with 'await' as they are asynchronous and return a promise. Please also note that the clipboard function of the small VSS catalogue writes 'Vehicle' with an uppercase 'V' so if you are working with the instance like we do in the example you will have to change it to a lowercase one. The Playground provides a barbones simulation meaning that .get() calls will always return a default value, .set() calls will accept values and .subscribe() calls will call the callback. There is however no effect on any background process and values of different API nodes don't corelate. This is just to have callable working API nodes for basic testing of your Prototype. For an actual simulation of any kind you will need to use Plugins



Interacting with Plugins directly: There are some situations where you'd might want to call functions of a Plugin directly. Since Plugins control Widgets the most likely Scenario is that you have a Widget you want to directly manipulate from your Prototypes code. For this you need the built package 'plugins':

import plugins


With this imported you can get access to any Plugin by name and call any functions it makes available:

kinetosis_plugin = plugins.get_plugin("Anti-Kinetosis")
kinetosis_plugin.load_signals()

Creating and using Plugins

Plugins are bound to a Model so any Prototype that belongs to the same Model will have access to the same Plugins. With enough planning Plugins and their Widgets can be made highly reusable. But since their simulations often are very specific to a certain Prototype it is very likely you will have to write your own. Regardless of that for any Prototype all available Plugins will always be loaded and made available.

Adding a new Plugin

Selecting Plugins Section.png

When you have opened a Model or Prototype the hamburger menu in the navigation bar will have an entry Plugins. Clicking on that will lead to the list of available Plugins to that Model.

Adding a Plugin.png

In the following screen you can modify existing Plugins. At the top of the list you find the option "New Plugin". If you click on that a panel will open. You have to give a Name for your plugin. This will be the reference in the code. Note: You can only choose names without whitespaces. The description is optional. The "JS Code" field must be filled with a link to the Plugin. Right now the Playground doesn't host Plugins so you will have to host the Plugin yourself.

Hosting a Plugin

The requirements for hosted Plugins are that the Playground needs direct access to the raw file via URL. Also the hosting MUST be https. There are a few options for this we recommend:


Option1: Hosting your Plugin via Github:

Hosting a Plugin via Github.png


Option2: Hosting your Plugin locally for faster Plugin testing: In this example we are using the Live Server Plugin for VSCode but many IDEs support similar Plugins and you can of course also just use any local Webserver you like.

  1. Create a new project with VS Code
  2. Inside VS Code, install the Live Server Plugin
  3. Write a <plugin_name>.js file
  4. Start Live Server plugin, you will get a URL like: http://localhost:5500/<plugin_name>.js
  5. Go to digital.auto Playground, add a plugin with the above URL
  6. Test your Plugin in a Prototype
  7. If the plugin is not working correctly, edit the file in Vscode, save, and reload the Page. Note: You will have to reload the entire page, switching between tabs on the Playground doesn't reload Plugins.


Working with Plugin code

const plugin = ({widgets, simulator, vehicle}) => {
  //Your Plugin code here
}


The example above shows the bare minimum any Plugin needs to contain. A Plugin is a function that gets passed three parameters by the Playground: 'widgets', 'simulator', 'vehicle'.



Registering Widgets: The 'widget' object provides a 'register' function that requires a Widget name by which the Widget will be referred in the Playground and a function that accepts a "box" parameter with an 'inject' method. That Box is the outline we define with the 'box' Parameter in the Dashboard Configuration.

widgets.register("testwidget", (box)>{
  const hello = document.createElement("div");
  const span = document.createElement("span");
  
  hello.appendChild(span);
  span.textContent = "hello world";

  box.injectNode(hello);
})

The example above shows a very basic 'hello world'-Widget. Widgets are just HTML Code that can be modified by and interact with the Plugin code with all the possibilities of the DOM environment. Obviously the possibilities here are "endless" but of course we don't want to always build everything from scratch, especially for simple visualizations.

That is why the Playground has a set of Reusables these are templates that can be imported to the Plugin and then used to build your own Widget on top. The reason they can't just be used out of the box is that we need the Plugin to connect them to whichever value or process in the simulation we want to visualize. A list of available Reusables and how they are used can be found here

import SignalPills from "https://playground-plugins.netlify.appU/reusable/SignalPills.js"

const plugin = ({widgets, simulator, vehicle}) => {
  widgets.register("testwidget", SignalPills([{signal: "Vehicle.Body.Windshield.Rear.Wiping. vehicle))
}

export default plugin;

The example above is using the 'SignalPills' Reusable. We are still using the 'widgets.register()' function and passing our own Widget name but instead of the function we pass the Reusable with some parameters. The 'SignalPills' Reusable requires a list of JSON Objects, that is because it can display up to three values. Each Object defines a "signal" or API node whose value it will show. The other Parameters in the object are for styling and metainformation (please refer to the guide on Reusables mentioned above). As a last parameter the Reusable requires the 'vehicle' object passed to the Plugin function.

And this is how the SignalPills Widget would look like in our example:

SignalPills on Dashboard.png



Accessing VSS Values inside a Plugin: In the section before we built our own basic Plugin and we tested a Reusable that was able to display the value of an API node. Now what if we want to do that in our own Widget? This is where the 'vehicle' object passed to the Plugn function comes in and this is also why the Reusable required it. The 'vehicle' object makes values of API (especially those modified by a Prototype) available to the Plugin. Access works as follows:

const value = await cehicle["Body.Windshield.Rear.Wiping.Intensity"].get()

The example above loads the current value of "vehicle.Body.Windshield.Rear.Wiping.Intensity" into a variable. Note: we are omitting the "vehicle" in front of the API node when using the vehicle object. The vehicle object is a map giving access to all available API nodes.



Changing the behavior of API Nodes in Prototype Code: We talked about that for many cases we might need a more sphisticated simulation and this is where we use the 'simulator' object passed to the Plugin function for. This can be used to override the behavior of any API node. The Simulator is a function that requires an exact API node as a string Note: with "Vehicle" in capital letters. Furthermore it requires the type of function we want to override (get / set) and lastly an async function to model the required behavior. The function has to be async because API nodes need to return a promise.

simulator("Vehicle.OBD.AmbientAirTemperature","get", async () => {
  return Math.floor(Math.random() * 1000);
})

simulator("Vehicle.Cabin.Seat.Row2.Pos1.Massage", "set", async (value) => {
  myFunction(value);
})

The example above shows two template API nodes being overridden. The first one overrides the get() function of a Sensor and would make that sensor return a random value every time it is accessed. Of course we can also write a Function that uses a lookup table, returns static values or makes complex calculations based on a more complex simulation. The second example overrides the set() function of an Actuator. In this case we want to react to a change made by the Prototype code. Here we are passing the value to some function that will influence our simulation but we could do virtually anything with this value, save it, do calculations or use it to influence the values of some other API nodes with anothes Simulator.

Advanced: Creating custom widgets

Creating custom UX elements

Creating custom data sources

Enabling re-use

General functions

Adding Media

Opened Hamburger.png

If you click on the hamburger menu in the navigation bar (pictured above) a menu will fold out. If you click on the option "Media" you will be redirected to the overview of all available media files (images and videos). Here you can upload new media to be used in your projects with the "Upload Media" button on the top right of the screen.

Managing Tags

The hamburger menu described in the section above has an option "Tags" clicking on it will lead you to the Tag category overview:

Tag Category overview.png

Here you can either add a new tag category by clicking on "New Tag Category", entering a name and selecting a color in the unfolding menu. or you can add tags to existing categories by clicking on the category you want to modify. This will bring you to an overview of all Tags available to this category:

Tags of category.png

Tags are represented by boxes with headers containing the tags name and optionally a representative image. Clicking on the box with the dotted outline and plus symbol will let you add a tag by entering a Name and optionally a description in the unfolding menu. If you want to add an image to a tag you have to click it and select the image in the following screen.